diff --git a/CHANGELOG.md b/CHANGELOG.md
index 33950b48f82425678c4770c42f46ec61f395ebef..57cf7f5ee5c714500dc006ea37f7fbd5b58baff9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,10 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added ###
 
+* Added examples for complex data models to documentation
+* extended apiutils with `resolve_reference(Property)`
+* is_reference function for Properties
+
 ### Changed ###
 
 ### Deprecated ###
 
+* `id_query(ids)` in apiutils
+
 ### Removed ###
 
 ### Fixed ###
@@ -20,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 * Unintuitive behavior of `Entity.role` after a `Entity(id).retrieve()` where
   the correct role is present now.
 * #53 Documentation of inheritance
+* #38 Dependencies in chunk-deletion of containers
 
 ### Security ###
 
diff --git a/src/caosdb/apiutils.py b/src/caosdb/apiutils.py
index 73074efc3057e0548c5abfd56ef3cf1ac9e9bf47..9192289a0b6518a2d6ec3abcdeca9d1d2c063d6d 100644
--- a/src/caosdb/apiutils.py
+++ b/src/caosdb/apiutils.py
@@ -31,6 +31,7 @@ Some simplified functions for generation of records etc.
 import sys
 import tempfile
 from collections.abc import Iterable
+import warnings
 from subprocess import call
 
 from caosdb.common.datatype import (BOOLEAN, DATETIME, DOUBLE, FILE, INTEGER,
@@ -86,9 +87,19 @@ def new_record(record_type, name=None, description=None,
 
 
 def id_query(ids):
-    q = "FIND Entity with " + " OR ".join(["id={}".format(id) for id in ids])
+    warnings.warn("Please use 'create_id_query', which only creates"
+                  "the string.", DeprecationWarning)
 
-    return execute_query(q)
+    return execute_query(create_id_query(ids))
+
+
+def create_id_query(ids):
+    return "FIND ENTITY WITH " + " OR ".join(
+        ["ID={}".format(id) for id in ids])
+
+
+def retrieve_entity_with_id(eid):
+    return execute_query("FIND ENTITY WITH ID={}".format(eid), unique=True)
 
 
 def retrieve_entities_with_ids(entities):
@@ -96,7 +107,9 @@ def retrieve_entities_with_ids(entities):
     step = 20
 
     for i in range(len(entities)//step+1):
-        collection.extend(id_query(entities[i*step:(i+1)*step]))
+        collection.extend(
+            execute_query(
+               create_id_query(entities[i*step:(i+1)*step])))
 
     return collection
 
@@ -707,3 +720,28 @@ def _apply_to_ids_of_entity(entity, func):
             else:
                 if prop.value is not None:
                     prop.value = func(prop.value)
+
+
+def resolve_reference(prop: Property):
+    """resolves the value of a reference property
+
+    The integer value is replaced with the entity object.
+    If the property is not a reference, then the function returns without
+    change.
+    """
+
+    if not prop.is_reference(server_retrieval=True):
+        return
+
+    if isinstance(prop.value, list):
+        referenced = []
+
+        for val in prop.value:
+            if isinstance(val, int):
+                referenced.append(retrieve_entity_with_id(val))
+            else:
+                referenced.append(val)
+        prop.value = referenced
+    else:
+        if isinstance(prop.value, int):
+            prop.value = retrieve_entity_with_id(prop.value)
diff --git a/src/caosdb/common/datatype.py b/src/caosdb/common/datatype.py
index eb8c1e4e0088f1924940a104ec3916b9d5d40f99..5434f5b6556a13f65754eacc66cb32231366e5b3 100644
--- a/src/caosdb/common/datatype.py
+++ b/src/caosdb/common/datatype.py
@@ -45,6 +45,8 @@ def LIST(datatype):
 
 def get_list_datatype(datatype):
     """ returns the datatype of the elements in the list """
+    if not isinstance(datatype, str):
+        return None
     match = re.match("LIST(<|&lt;)(?P<datatype>.*)(>|&gt;)", datatype)
 
     if match is not None:
@@ -66,6 +68,10 @@ def is_reference(datatype):
     RecordTypes
     """
 
+    if datatype is None:
+        raise ValueError("Cannot decide whether datatype is reference if None"
+                         " is supplied")
+
     if datatype in [DOUBLE, BOOLEAN, INTEGER, TEXT, DATETIME]:
         return False
     elif is_list_datatype(datatype):
diff --git a/src/caosdb/common/models.py b/src/caosdb/common/models.py
index b054496d0255e6112b59f938d573a36bb5890b37..89397a6e5762fde5afebe76cb12d7dc5346b014c 100644
--- a/src/caosdb/common/models.py
+++ b/src/caosdb/common/models.py
@@ -31,6 +31,7 @@ from __future__ import print_function, unicode_literals
 import re
 import sys
 from builtins import str
+from copy import deepcopy
 from functools import cmp_to_key
 from hashlib import sha512
 from os import listdir
@@ -40,26 +41,23 @@ from sys import hexversion
 from tempfile import NamedTemporaryFile
 from warnings import warn
 
-from caosdb.common.datatype import (BOOLEAN, DATETIME, DOUBLE, INTEGER, TEXT)
-from caosdb.common.versioning import Version
+from caosdb.common.datatype import (BOOLEAN, DATETIME, DOUBLE, INTEGER, TEXT,
+                                    is_list_datatype, is_reference)
 from caosdb.common.state import State
 from caosdb.common.utils import uuid, xml2str
+from caosdb.common.versioning import Version
 from caosdb.configuration import get_config
 from caosdb.connection.connection import get_connection
 from caosdb.connection.encode import MultipartParam, multipart_encode
-from caosdb.exceptions import (AmbiguousEntityError,
-                               AuthorizationError,
-                               CaosDBException, CaosDBConnectionError,
-                               ConsistencyError,
-                               EmptyUniqueQueryError,
+from caosdb.exceptions import (AmbiguousEntityError, AuthorizationError,
+                               CaosDBConnectionError, CaosDBException,
+                               ConsistencyError, EmptyUniqueQueryError,
                                EntityDoesNotExistError, EntityError,
-                               EntityHasNoDatatypeError,
-                               MismatchingEntitiesError,
-                               QueryNotUniqueError, TransactionError,
-                               UniqueNamesError,
+                               EntityHasNoDatatypeError, HTTPURITooLongError,
+                               MismatchingEntitiesError, QueryNotUniqueError,
+                               TransactionError, UniqueNamesError,
                                UnqualifiedParentsError,
-                               UnqualifiedPropertiesError,
-                               HTTPURITooLongError)
+                               UnqualifiedPropertiesError)
 from lxml import etree
 
 _ENTITY_URI_SEGMENT = "Entity"
@@ -580,6 +578,7 @@ class Entity(object):
             entity, or name.
 
         """
+
         if isinstance(key, int):
             for p in self.parents:
                 if p.id is not None and int(p.id) == int(key):
@@ -588,14 +587,17 @@ class Entity(object):
             if key.id is not None:
                 # first try by id
                 found = self.get_parent(int(key.id))
+
                 if found is not None:
                     return found
             # otherwise by name
+
             return self.get_parent(key.name)
         else:
             for p in self.parents:
                 if (p.name is not None
                         and str(p.name).lower() == str(key).lower()):
+
                     return p
 
         return None
@@ -680,6 +682,7 @@ class Entity(object):
             special_selector = None
 
         # iterating through the entity tree according to the selector
+
         for subselector in selector:
             # selector does not match the structure, we cannot get a
             # property of non-entity
@@ -691,11 +694,13 @@ class Entity(object):
 
             # selector does not match the structure, we did not get a
             # property
+
             if prop is None:
                 return None
 
             # if the property is a reference, we are interested in the
             # corresponding entities attributes
+
             if isinstance(prop.value, Entity):
                 ref = prop.value
 
@@ -704,6 +709,7 @@ class Entity(object):
                 ref = prop
 
         # if we saved a special selector before, apply it
+
         if special_selector is None:
             return prop.value
         else:
@@ -837,6 +843,7 @@ class Entity(object):
         assert isinstance(xml, etree._Element)
 
         # unwrap wrapped entity
+
         if self._wrapped_entity is not None:
             xml = self._wrapped_entity.to_xml(xml, add_properties)
 
@@ -1078,6 +1085,7 @@ class Entity(object):
 
             if len(c) == 1:
                 c[0].messages.extend(c.messages)
+
                 return c[0]
 
             raise QueryNotUniqueError("This retrieval was not unique!!!")
@@ -1502,6 +1510,42 @@ class Property(Entity):
 
         return super(Property, self).to_xml(xml, add_properties)
 
+    def is_reference(self, server_retrieval=False):
+        """Returns whether this Property is a reference
+
+        Parameters
+        ----------
+        server_retrieval : bool, optional
+            If True and the datatype is not set, the Property is retrieved from the server, by default False
+
+        Returns
+        -------
+        bool, NoneType
+            Returns whether this Property is a reference or None if a server call is needed to
+            check correctly, but server_retrieval is set to False.
+
+        """
+
+        if self.datatype is None:
+
+            if not self.is_valid():
+                # this is a workaround to prevent side effects
+                # since retrieve currently changes the object
+
+                if server_retrieval:
+                    tmp_prop = deepcopy(self)
+                    tmp_prop.retrieve()
+
+                    return tmp_prop.is_reference()
+                else:
+                    return None
+            else:
+                # a valid property without datatype has to be an RT
+
+                return True
+        else:
+            return is_reference(self.datatype)
+
 
 class Message(object):
 
@@ -2150,6 +2194,7 @@ class _Messages(dict):
             else:
                 raise TypeError(
                     "('description', 'body'), ('body'), or 'body' expected.")
+
         if isinstance(value, Message):
             body = value.body
             description = value.description
@@ -2321,6 +2366,7 @@ def _deletion_sync(e_local, e_remote):
     except KeyError:
         # deletion info wasn't there
         e_local.messages = e_remote.messages
+
         return
 
     _basic_sync(e_local, e_remote)
@@ -2513,6 +2559,7 @@ class Container(list):
         tmpid = 0
 
         # users might already have specified some tmpids. -> look for smallest.
+
         for e in self:
             tmpid = min(tmpid, Container._get_smallest_tmpid(e))
         tmpid -= 1
@@ -2732,6 +2779,7 @@ class Container(list):
         used_remote_entities = []
 
         # match by cuid
+
         for local_entity in self:
 
             sync_dict[local_entity] = None
@@ -2760,6 +2808,7 @@ class Container(list):
                         raise MismatchingEntitiesError(msg)
 
         # match by id
+
         for local_entity in self:
             if sync_dict[local_entity] is None and local_entity.id is not None:
                 sync_remote_entities = []
@@ -2784,6 +2833,7 @@ class Container(list):
                         raise MismatchingEntitiesError(msg)
 
         # match by path
+
         for local_entity in self:
             if (sync_dict[local_entity] is None
                     and local_entity.path is not None):
@@ -2813,6 +2863,7 @@ class Container(list):
                         raise MismatchingEntitiesError(msg)
 
         # match by name
+
         for local_entity in self:
             if (sync_dict[local_entity] is None
                     and local_entity.name is not None):
@@ -2862,7 +2913,60 @@ class Container(list):
 
         return sync_dict
 
-    def delete(self, raise_exception_on_error=True, flags=None):
+    def _test_dependencies_in_container(self, container):
+        """This function returns those elements of a given container that are a dependency of another element of the same container.
+
+        Args:
+            container (Container): a caosdb container
+
+        Returns:
+            [set]: a set of unique elements that are a dependency of another element of `container`
+        """
+        item_id = set()
+        is_parent = set()
+        is_property = set()
+        is_being_referenced = set()
+        dependent_parents = set()
+        dependent_properties = set()
+        dependent_references = set()
+        dependencies = set()
+
+        for container_item in container:
+            item_id.add(container_item.id)
+
+            for parents in container_item.get_parents():
+                is_parent.add(parents.id)
+
+            for references in container_item.get_properties():
+                if is_reference(references.datatype):
+                    # add only if it is a reference, not a property
+
+                    if isinstance(references.value, int):
+                        is_being_referenced.add(references.value)
+                    elif is_list_datatype(references.datatype):
+                        for list_item in references.value:
+                            if isinstance(list_item, int):
+                                is_being_referenced.add(list_item)
+                            else:
+                                is_being_referenced.add(list_item.id)
+                    else:
+                        try:
+                            is_being_referenced.add(references.value.id)
+                        except AttributeError:
+                            pass
+
+                if hasattr(references, 'id'):
+                    is_property.add(references.id)
+
+        dependent_parents = item_id.intersection(is_parent)
+        dependent_properties = item_id.intersection(is_property)
+        dependent_references = item_id.intersection(is_being_referenced)
+        dependencies = dependent_parents.union(dependent_references)
+        dependencies = dependencies.union(dependent_properties)
+
+        return dependencies
+
+    def delete(self, raise_exception_on_error=True, flags=None, chunk_size=100):
         """Delete all entities in this container.
 
         Entities are identified via their id if present and via their
@@ -2873,16 +2977,45 @@ class Container(list):
         this happens, none of them will be deleted. It occurs an error
         instead.
         """
-        chunk_size = 100
         item_count = len(self)
         # Split Container in 'chunk_size'-sized containers (if necessary) to avoid error 414 Request-URI Too Long
+
         if item_count > chunk_size:
+            dependencies = self._test_dependencies_in_container(self)
+            '''
+            If there are as many dependencies as entities in the container and it is larger than chunk_size it cannot be split and deleted.
+            This case cannot be handled at the moment.
+            '''
+
+            if len(dependencies) == item_count:
+                if raise_exception_on_error:
+                    te = TransactionError(
+                        msg="The container is too large and with too many dependencies within to be deleted.",
+                        container=self)
+                    raise te
+
+                return self
+
+            # items which have to be deleted later because of dependencies.
+            dependencies_delete = Container()
+
             for i in range(0, int(item_count/chunk_size)+1):
                 chunk = Container()
+
                 for j in range(i*chunk_size, min(item_count, (i+1)*chunk_size)):
-                    chunk.append(self[j])
+                    if len(dependencies):
+                        if self[j].id in dependencies:
+                            dependencies_delete.append(self[j])
+                        else:
+                            chunk.append(self[j])
+                    else:
+                        chunk.append(self[j])
+
                 if len(chunk):
                     chunk.delete()
+            if len(dependencies_delete):
+                dependencies_delete.delete()
+
             return self
 
         if len(self) == 0:
@@ -3520,6 +3653,7 @@ class ACL():
         result._priority_grants.update(self._priority_grants)
         result._priority_denials.update(other._priority_denials)
         result._priority_denials.update(self._priority_denials)
+
         return result
 
     def __eq__(self, other):
@@ -3810,6 +3944,7 @@ class Query():
         connection = get_connection()
 
         flags = self.flags
+
         if cache is False:
             flags["cache"] = "false"
         query_dict = dict(flags)
@@ -3836,9 +3971,11 @@ class Query():
             if len(cresp) > 1 and raise_exception_on_error:
                 raise QueryNotUniqueError(
                     "Query '{}' wasn't unique.".format(self.q))
+
             if len(cresp) == 0 and raise_exception_on_error:
                 raise EmptyUniqueQueryError(
                     "Query '{}' found no results.".format(self.q))
+
             if len(cresp) == 1:
                 r = cresp[0]
                 r.messages.extend(cresp.messages)
@@ -3945,6 +4082,7 @@ class Info():
 
         for e in xml:
             m = _parse_single_xml_element(e)
+
             if isinstance(m, UserInfo):
                 self.user_info = m
             else:
@@ -4104,13 +4242,16 @@ def _evaluate_and_add_error(parent_error, ent):
         Parent error with new exception(s) attached to it.
 
     """
+
     if isinstance(ent, (Entity, QueryTemplate)):
         # Check all error messages
         found114 = False
         found116 = False
+
         for err in ent.get_errors():
             # Evaluate specific EntityErrors depending on the error
             # code
+
             if err.code is not None:
                 if int(err.code) == 101:  # ent doesn't exist
                     new_exc = EntityDoesNotExistError(entity=ent,
@@ -4127,6 +4268,7 @@ def _evaluate_and_add_error(parent_error, ent):
                     found114 = True
                     new_exc = UnqualifiedPropertiesError(entity=ent,
                                                          error=err)
+
                     for prop in ent.get_properties():
                         new_exc = _evaluate_and_add_error(new_exc,
                                                           prop)
@@ -4134,6 +4276,7 @@ def _evaluate_and_add_error(parent_error, ent):
                     found116 = True
                     new_exc = UnqualifiedParentsError(entity=ent,
                                                       error=err)
+
                     for par in ent.get_parents():
                         new_exc = _evaluate_and_add_error(new_exc,
                                                           par)
@@ -4144,21 +4287,28 @@ def _evaluate_and_add_error(parent_error, ent):
             parent_error.add_error(new_exc)
         # Check for possible errors in parents and properties that
         # weren't detected up to here
+
         if not found114:
             dummy_err = EntityError(entity=ent)
+
             for prop in ent.get_properties():
                 dummy_err = _evaluate_and_add_error(dummy_err, prop)
+
             if dummy_err.errors:
                 parent_error.add_error(dummy_err)
+
         if not found116:
             dummy_err = EntityError(entity=ent)
+
             for par in ent.get_parents():
                 dummy_err = _evaluate_and_add_error(dummy_err, par)
+
             if dummy_err.errors:
                 parent_error.add_error(dummy_err)
 
     elif isinstance(ent, Container):
         parent_error.container = ent
+
         if ent.get_errors() is not None:
             parent_error.code = ent.get_errors()[0].code
             # In the highly unusual case of more than one error
@@ -4166,6 +4316,7 @@ def _evaluate_and_add_error(parent_error, ent):
             parent_error.msg = '\n'.join(
                 [x.description for x in ent.get_errors()])
         # Go through all container elements and add them:
+
         for elt in ent:
             parent_error = _evaluate_and_add_error(parent_error, elt)
 
@@ -4191,10 +4342,12 @@ def raise_errors(arg0):
     transaction_error = _evaluate_and_add_error(TransactionError(),
                                                 arg0)
     # Raise if any error was found
+
     if len(transaction_error.all_errors) > 0:
         raise transaction_error
     # Cover the special case of an empty container with error
     # message(s) (e.g. query syntax error)
+
     if (transaction_error.container is not None and
             transaction_error.container.has_errors()):
         raise transaction_error
diff --git a/src/caosdb/yamlapi.py b/src/caosdb/yamlapi.py
index b2e527983cbbeca2ee71a63e87f487d24d7c0301..9a69a5276804727084af65c6568b22833e8be596 100644
--- a/src/caosdb/yamlapi.py
+++ b/src/caosdb/yamlapi.py
@@ -73,6 +73,14 @@ def dict_to_xml(d):
 
 
 def yaml_to_xml(yamlstr):
+    """Load a yaml document from yamlstr and converts it to XML.
+
+    Parameters
+    ----------
+    yamlstr : str
+        The string to load the yaml document from.
+
+    """
     return dict_to_xml(yaml.load(yamlstr))
 
 
diff --git a/src/doc/tutorials/complex_data_models.rst b/src/doc/tutorials/complex_data_models.rst
new file mode 100644
index 0000000000000000000000000000000000000000..0fa868e78bb45a2905dc99392a3a28a9832d369e
--- /dev/null
+++ b/src/doc/tutorials/complex_data_models.rst
@@ -0,0 +1,76 @@
+Complex Data Models
+-------------------
+
+With CaosDB it is possible to create very complex data models.
+
+E.g. it is possible to add properties to properties to cover complex relations
+in data management workflows.
+
+One example for a use case is meta data that is added to very specific properties of
+datasets, e.g. data privacy information can be added to properties which themselves
+could already be considered meta data of a dataset.
+
+The example below tries to cover some complex cases for data models:
+
+Examples
+--------
+
+.. code-block:: python3
+
+   import caosdb as db
+
+   # Create two record types with descriptions:
+   rt1 = db.RecordType(name="TypeA", description="The first type")
+   rt2 = db.RecordType(name="TypeB", description="The second type")
+
+   # Create a record using the first record type as parent:
+   r1 = db.Record(name="Test_R_1", description="A record")
+   r1.add_parent(rt1)
+
+   # Create two files (the files named test.txt and testfile2.txt should exist in the
+   # current working directory:
+   f1 = db.File(name="Test file", path="/test.txt", file="test.txt")
+   f2 = db.File(name="Test file 2", path="/testfile2.txt", file="testfile2.txt")
+
+   # Create two properties with different data types:
+   p1 = db.Property(name="TestFileProperty", datatype=db.FILE)
+   p2 = db.Property(name="TestDoubleProperty", datatype=db.DOUBLE, unit="m")
+   p3 = db.Property(name="TestIntegerProperty", datatype=db.INTEGER, unit="s")
+
+   # Create a reference property that points to records of record type 2:
+   p4 = db.Property(name="TestReferenceProperty", datatype=rt2)
+
+   # Create a complex record:
+   r2 = db.Record(name="Test_R_2", description="A second record")
+   r2.add_parent(rt2)
+   r2.add_property(rt1, value=r1)  # this is a reference to the first record type
+   r2.add_property(p1, value=f1)  # this is a reference to the first file
+   r2.add_property(p2, value=24.8)  # this is a double property with a value
+   r2.add_property(p3, value=1)  # this is an integer property with a value
+
+   # Very complex part of the data model:
+   # Case 1: File added to another file
+   f2.add_property(p1, value=f1)  # this adds a file property with value first file
+		                  # to the second file
+
+   # Case 2: Property added to a property
+   p2.add_property(p3, value=27)  # this adds an integer property with value 27 to the
+		                  # double property
+
+   # Case 3: Reference property added to a property
+   # The property p2 now has two sub properties, one is pointing to
+   # record p2 which itself has the property p2, therefore this can be
+   # considered a loop in the data model.
+   p2.add_property(p4, value=r2)  # this adds a reference property pointing to
+		                  # record 2 to the double property
+
+   # Insert a container containing all the newly created entities:
+   c = db.Container().extend([rt1, rt2, r1, r2, f1, p1, p2, p3, f2, p4])
+   c.insert()
+
+   # Useful for testing: wait until the user presses a key
+   # Meanwhile have a look at the WebUI: You can e.g. query "FIND Test*" to view
+   # all the entities created here and see the relations and links between them.
+   b = input("Press any key to cleanup.")
+   # cleanup everything after the user presses any button.
+   c.delete()
diff --git a/src/doc/tutorials/index.rst b/src/doc/tutorials/index.rst
index 3889edb8f47e973cc7ae25c9134d75cfeab95f65..79068e9201498c87b2eb61b4ffbea0969845b404 100644
--- a/src/doc/tutorials/index.rst
+++ b/src/doc/tutorials/index.rst
@@ -15,4 +15,5 @@ advanced usage of the Python client.
    Data-Insertion
    errors
    data-model-interface
-
+   complex_data_models
+      
diff --git a/unittests/test_apiutils.py b/unittests/test_apiutils.py
index c560b5e3c7c424b762bc8381c7cc9f42617288d0..264b4c880022e6fd135426864bf9c5084c047eca 100644
--- a/unittests/test_apiutils.py
+++ b/unittests/test_apiutils.py
@@ -29,7 +29,8 @@
 import caosdb as db
 import pickle
 import tempfile
-from caosdb.apiutils import apply_to_ids
+from caosdb.apiutils import apply_to_ids, create_id_query, resolve_reference
+import caosdb.apiutils
 from .test_property import testrecord
 
 
@@ -62,3 +63,42 @@ def test_apply_to_ids():
     assert rec.parents[0].id == -3456
     assert rec.properties[0].id == -23345
     assert rec.id == -23
+
+
+def test_id_query():
+    ids = [1, 2, 3, 4, 5]
+    assert create_id_query(ids) == 'FIND ENTITY WITH ID=1 OR ID=2 OR ID=3 OR ID=4 OR ID=5'
+
+
+def test_resolve_reference():
+    original_retrieve_entity_with_id = caosdb.apiutils.retrieve_entity_with_id
+    caosdb.apiutils.retrieve_entity_with_id = lambda eid: db.Record(id=eid)
+
+    prop = db.Property(id=1, datatype=db.REFERENCE, value=100)
+    prop.is_valid = lambda: True
+    items = [200, 300, 400]
+    prop_list = db.Property(datatype=db.LIST(db.REFERENCE), value=items)
+    prop_list2 = db.Property(datatype=db.LIST(db.REFERENCE), value=[db.Record(id=500)])
+    resolve_reference(prop)
+    resolve_reference(prop_list)
+    resolve_reference(prop_list2)
+    assert prop.value.id == 100
+    assert isinstance(prop.value, db.Entity)
+
+    prop_list_ids = []
+    for i in prop_list.value:
+        prop_list_ids.append(i.id)
+        assert isinstance(i, db.Entity)
+    assert prop_list_ids == items
+
+    for i in prop_list2.value:
+        assert i.id == 500
+        assert isinstance(i, db.Entity)
+
+    no_reference = db.Property(id=5000, datatype=db.INTEGER, value=2)
+    resolve_reference(no_reference)
+    assert no_reference.value == 2
+    assert no_reference.datatype is db.INTEGER
+
+    # restore retrive_entity_with_id
+    caosdb.apiutils.retrieve_entity_with_id = original_retrieve_entity_with_id
diff --git a/unittests/test_container.py b/unittests/test_container.py
index b34055372fc83a5608ffcf54423a601001add12b..0ac4be44826825aa3302119c8bca08f335ab68d3 100644
--- a/unittests/test_container.py
+++ b/unittests/test_container.py
@@ -25,28 +25,28 @@
 """Tests for the Container class."""
 from __future__ import absolute_import
 
-import caosdb as c
+import caosdb as db
 
 
 def test_get_property_values():
-    rt_house = c.RecordType("House")
-    rt_window = c.RecordType("Window")
-    rt_owner = c.RecordType("Owner")
-    p_height = c.Property("Height", datatype=c.DOUBLE)
+    rt_house = db.RecordType("House")
+    rt_window = db.RecordType("Window")
+    rt_owner = db.RecordType("Owner")
+    p_height = db.Property("Height", datatype=db.DOUBLE)
 
-    window = c.Record().add_parent(rt_window)
+    window = db.Record().add_parent(rt_window)
     window.id = 1001
     window.add_property(p_height, 20.5, unit="m")
 
-    owner = c.Record("The Queen").add_parent(rt_owner)
+    owner = db.Record("The Queen").add_parent(rt_owner)
 
-    house = c.Record("Buckingham Palace")
+    house = db.Record("Buckingham Palace")
     house.add_parent(rt_house)
     house.add_property(rt_owner, owner)
     house.add_property(rt_window, window)
     house.add_property(p_height, 40.2, unit="ft")
 
-    container = c.Container()
+    container = db.Container()
     container.extend([
         house,
         owner
@@ -77,3 +77,70 @@ def test_get_property_values():
     assert container.get_property_values("non-existing") == [(None,), (None,)]
     assert container.get_property_values("name") == [(house.name,),
                                                      (owner.name,)]
+
+
+def test_container_dependencies_for_deletion():
+    not_included_rt = 1000
+    rt = db.RecordType("Just a RecordType")
+    rt.id = 1001
+    rt_record_with_parent = db.RecordType("Records with parent")
+    rt_record_with_parent.id = 1005
+    property_which_is_not_a_record = db.Property(
+        "Normal Property", datatype=db.DOUBLE, value=1006)
+    property_which_is_not_a_record.id = 1006
+    property_which_shall_be_deleted = db.Property(
+        "Normal Property 2", datatype=db.DOUBLE, value=1006)
+    property_which_shall_be_deleted .id = 1007
+
+    record_without_dependencies = db.Record().add_parent(not_included_rt)
+    record_without_dependencies.id = 2003
+
+    record_referenced = db.Record().add_parent(not_included_rt)
+    record_referenced.id = 2002
+    record_with_dependencies = db.Record().add_parent(not_included_rt)
+    record_with_dependencies.id = 2004
+    record_with_dependencies.add_property(not_included_rt,
+                                          record_referenced,
+                                          datatype="not_included_rt")
+
+    record_with_parent = db.Record().add_parent(rt_record_with_parent)
+    record_with_parent.id = 2005
+
+    record_with_property_which_is_not_a_record = db.Record(
+    ).add_parent(not_included_rt)
+    record_with_property_which_is_not_a_record.id = 2006
+    record_with_property_which_is_not_a_record.add_property(
+        property_which_is_not_a_record)
+    record_with_property_which_is_not_a_record.add_property(
+        property_which_shall_be_deleted)
+
+    container = db.Container()
+    container.extend([
+        rt,
+        rt_record_with_parent,  # 1005, dependency
+        record_without_dependencies,
+        property_which_shall_be_deleted,  # 1007, dependency
+        record_referenced,  # 2002, dependency
+        record_with_dependencies,
+        record_with_parent,
+        record_with_property_which_is_not_a_record
+    ])
+    assert (db.Container()._test_dependencies_in_container(container)
+            == {2002, 1005, 1007})
+
+
+def test_container_dependencies_for_deletion_with_lists():
+    not_included_rt = 1000
+
+    record_referenced = db.Record().add_parent(not_included_rt)
+    record_referenced.id = 2001
+
+    record_with_list = db.Record().add_parent(not_included_rt)
+    record_with_list.id = 2002
+    record_with_list.add_property(not_included_rt, datatype=db.LIST(
+        not_included_rt), value=[record_referenced, 2003, 2004, 2005, 2006])
+
+    container = db.Container()
+    container.extend([record_with_list, record_referenced])
+
+    assert db.Container()._test_dependencies_in_container(container) == {2001}
diff --git a/unittests/test_property.py b/unittests/test_property.py
index 752ee01f0eafef14dbffd1e62c99d1c816c45d05..834b1be582c58c60f70331de9cb0d0d6414fd6c9 100644
--- a/unittests/test_property.py
+++ b/unittests/test_property.py
@@ -24,9 +24,10 @@
 # ** end header
 #
 """Tests for the Property class."""
+import caosdb as db
+from caosdb import Entity, Property, Record
 # pylint: disable=missing-docstring
 from lxml import etree
-from caosdb import Entity, Property, Record
 
 parser = etree.XMLParser(remove_comments=True)
 testrecord = Record._from_xml(Record(),
@@ -89,3 +90,47 @@ def test_get_property_with_entity():
 def test_selected_reference_list():
     assert len(testrecord.get_property("Conductor").value) == 1
     assert isinstance(testrecord.get_property("Conductor").value[0], Entity)
+
+
+def test_is_reference():
+    PROPS = {
+        10:  db.INTEGER,
+        20:  db.REFERENCE,
+        30:  "SomeRT",
+    }
+
+    def dummy_retrieve(self):
+        self.datatype = PROPS[self.id]
+        self.is_valid = lambda: True
+    # replace retrieve function by dummy
+    real_retrieve = Entity.retrieve
+    Entity.retrieve = dummy_retrieve
+
+    p1 = Property(id=1, datatype=db.INTEGER)
+    p2 = Property(id=2, datatype=db.DOUBLE)
+    p3 = Property(id=3, datatype=db.TEXT)
+    p4 = Property(id=4, datatype=db.DATETIME)
+    p5 = Property(id=5, datatype=db.BOOLEAN)
+    p6 = Property(id=6, datatype=db.REFERENCE)
+    assert p1.is_reference() is False
+    assert p2.is_reference() is False
+    assert p3.is_reference() is False
+    assert p4.is_reference() is False
+    assert p5.is_reference() is False
+    assert p6.is_reference() is True
+
+    p7 = Property(id=7)
+    p8 = Property(id=8, value=db.RecordType(id=1000))
+    p8.is_valid = lambda: True
+    assert p7.is_reference() is None  # cannot be resolved without calling a server
+    assert p8.is_reference() is True
+
+    p10 = Property(id=10)
+    p20 = Property(id=20)
+    p30 = Property(id=30)
+    assert p10.is_reference(server_retrieval=True) is False
+    assert p20.is_reference(server_retrieval=True) is True
+    assert p30.is_reference(server_retrieval=True) is True
+
+    # restore retrieve function with original
+    Entity.retrieve = real_retrieve