diff --git a/src/caosdb/apiutils.py b/src/caosdb/apiutils.py
index a46e30375b924d358448e73aece61562c36c700b..3d0e3883637318f7cef1477e9d1765e761179b4b 100644
--- a/src/caosdb/apiutils.py
+++ b/src/caosdb/apiutils.py
@@ -404,7 +404,6 @@ def merge_entities(entity_a: Entity, entity_b: Entity, merge_references_with_emp
     # Compare both entities:
     diff_r1, diff_r2 = compare_entities(
         entity_a, entity_b, compare_referenced_records=merge_references_with_empty_diffs)
-
     # Go through the comparison and try to apply changes to entity_a:
     for key in diff_r2["parents"]:
         entity_a.add_parent(entity_b.get_parent(key))
@@ -430,6 +429,7 @@ def merge_entities(entity_a: Entity, entity_b: Entity, merge_references_with_emp
                         setattr(entity_a.get_property(key), attribute,
                                 diff_r2["properties"][key][attribute])
                     else:
+                        print(entity_a, entity_b)
                         raise EntityMergeConflictError(
                             f"Entity a ({entity_a.id}, {entity_a.name}) "
                             f"has a Property '{key}' with {attribute}="
@@ -556,13 +556,13 @@ def resolve_reference(prop: Property):
         referenced = []
 
         for val in prop.value:
-            if isinstance(val, int):
+            if isinstance(val, (int, str)):
                 referenced.append(retrieve_entity_with_id(val))
             else:
                 referenced.append(val)
         prop.value = referenced
     else:
-        if isinstance(prop.value, int):
+        if isinstance(prop.value, (int, str)):
             prop.value = retrieve_entity_with_id(prop.value)
 
 
diff --git a/src/caosdb/common/models.py b/src/caosdb/common/models.py
index ee478c4a0c55818ce3e78aec0d4580f0dd6ea864..35c6720589c37a4ee5b8160e29a262f180e628be 100644
--- a/src/caosdb/common/models.py
+++ b/src/caosdb/common/models.py
@@ -82,6 +82,30 @@ NONE = "NONE"
 SPECIAL_ATTRIBUTES = ["name", "role", "datatype", "description",
                       "id", "path", "checksum", "size"]
 
+_EXPERIMENTAL_STRING_IDS = None
+
+
+def experimental_string_ids(switch_on=None):
+    global _EXPERIMENTAL_STRING_IDS
+    if switch_on is not None:
+        _EXPERIMENTAL_STRING_IDS = switch_on
+    if _EXPERIMENTAL_STRING_IDS is None:
+        _EXPERIMENTAL_STRING_IDS = get_config().getboolean("Misc", "experimental_string_ids", fallback=False)
+    return _EXPERIMENTAL_STRING_IDS
+
+
+def entity_id(eid):
+    if experimental_string_ids():
+        return str(eid)
+    else:
+        return int(eid)
+
+
+def is_temporary_id(eid):
+    if experimental_string_ids():
+        return entity_id(eid).startswith("-")
+    return entity(eid) < 0
+
 
 class Entity:
 
@@ -213,7 +237,7 @@ class Entity:
     @id.setter
     def id(self, new_id):
         if new_id is not None:
-            self.__id = int(new_id)
+            self.__id = entity_id(new_id)
         else:
             self.__id = None
 
@@ -880,12 +904,12 @@ out: List[Entity]
 
         if isinstance(key, int):
             for p in self.parents:
-                if p.id is not None and int(p.id) == int(key):
+                if p.id is not None and str(p.id) == str(key):
                     return p
         elif isinstance(key, Entity):
             if key.id is not None:
                 # first try by id
-                found = self.get_parent(int(key.id))
+                found = self.get_parent(key.id)
 
                 if found is not None:
                     return found
@@ -893,6 +917,10 @@ out: List[Entity]
 
             return self.get_parent(key.name)
         else:
+            # try id (case-sensitive), then name (case-insensitive)
+            for p in self.parents:
+                if p.id is not None and str(p.id) == str(key):
+                    return p
             for p in self.parents:
                 if (p.name is not None
                         and str(p.name).lower() == str(key).lower()):
@@ -940,10 +968,13 @@ out: List[Entity]
         # int given
         elif isinstance(pattern, int):
             for p in self.properties:
-                if p.id is not None and int(p.id) == int(pattern):
+                if p.id is not None and str(p.id) == str(pattern):
                     return p
         # str given
         elif isinstance(pattern, str):
+            for p in self.properties:
+                if p.id is not None and str(p.id) == str(pattern):
+                    return p
             for p in self.properties:
                 if (p.name is not None
                         and str(p.name).lower() == str(pattern).lower()):
@@ -1260,13 +1291,13 @@ out: List[Entity]
         if isinstance(entity, Entity):
             entity.role = elem.tag
         entity._cuid = elem.get("cuid")
-        entity.id = elem.get("id")  # @ReservedAssignment
+        entity.id = elem.get("id")
         entity.name = elem.get("name")
         entity.description = elem.get("description")
         entity.path = elem.get("path")
         entity._checksum = elem.get("checksum")
         entity._size = elem.get("size")
-        entity.datatype = elem.get("datatype")  # @ReservedAssignment
+        entity.datatype = elem.get("datatype")
         entity.unit = elem.get("unit")
         entity.file = elem.get("file")
 
@@ -1511,11 +1542,6 @@ def _parse_value(datatype, value):
         else:
             raise ValueError("Boolean value was {}.".format(value))
 
-    # Datetime and text are returned as-is
-    if datatype in [DATETIME, TEXT]:
-        if isinstance(value, str):
-            return value
-
     # deal with collections
     if isinstance(datatype, str):
         matcher = re.compile(r"^(?P<col>[^<]+)<(?P<dt>[^>]+)>$")
@@ -1541,34 +1567,26 @@ def _parse_value(datatype, value):
 
     # This is for a special case, where the xml parser could not differentiate
     # between single values and lists with one element. As
-    if hasattr(value, "__len__") and len(value) == 1:
+    if hasattr(value, "__len__") and len(value) == 1 and not isinstance(value, str):
         return _parse_value(datatype, value[0])
 
+    if isinstance(value, list):
+        raise TypeError(
+            "Invalid datatype: List valued properties must be announced by "
+            "the datatype.\n" + f"Datatype: {datatype}\nvalue: {value}")
+
+    if datatype in [DATETIME, TEXT]:
+        return str(value)
+
     # deal with references
     if isinstance(value, Entity):
         return value
 
-    if isinstance(value, str) and "@" in value:
-        # probably this is a versioned reference
-
+    try:
+        return entity_id(value)
+    except ValueError:
+        # reference via name or we have string ids.
         return str(value)
-    else:
-        # for unversioned references
-        try:
-            return int(value)
-        except ValueError:
-            # reference via name
-
-            return str(value)
-        except TypeError as te:
-            # deal with invalid XML: List of values without appropriate datatype
-            if isinstance(value, list):
-                raise TypeError(
-                    "Invalid datatype: List valued properties must be announced by "
-                    "the datatype.\n" + f"Datatype: {datatype}\nvalue: {value}")
-            else:
-                # Everything else that's not related to wrong list assignments
-                raise te
 
 
 def _log_request(request, xml_body=None):
@@ -1592,7 +1610,7 @@ class QueryTemplate():
 
     def __init__(self, id=None, name=None, query=None, description=None):  # @ReservedAssignment
 
-        self.id = (int(id) if id is not None else None)
+        self.id = (entity_id(id) if id is not None else None)
         self.role = "QueryTemplate"
         self.name = name
         self.description = description
@@ -1701,7 +1719,7 @@ class QueryTemplate():
                         q.version = child
                     elif isinstance(child, Permissions):
                         q.permissions = child
-            q.id = int(xml.get("id"))
+            q.id = entity_id(xml.get("id"))
 
             return q
         else:
@@ -2718,13 +2736,8 @@ class Container(list):
     """
 
     _debug = staticmethod(
-        lambda: (
-            get_config().getint(
-                "Container",
-                "debug") if get_config().has_section("Container") and
-            get_config().get(
-                "Container",
-                "debug") is not None else 0))
+        lambda: get_config().getint("Container", "debug", fallback=0)
+    )
 
     def is_valid(self):
         for e in self:
@@ -2784,7 +2797,7 @@ class Container(list):
 
         for e in self:
             if e.id:
-                if e.id == int(id):
+                if str(e.id) == str(id):
                     return e
         raise KeyError("No entity with such id (" + str(id) + ")!")
 
@@ -2873,15 +2886,15 @@ class Container(list):
         elif isinstance(entity, int):
             super().append(Entity(id=entity))
         elif hasattr(entity, "encode"):
-            super().append(Entity(name=entity))
+            if experimental_string_ids():
+                super().append(Entity(id=entity))
+            else:
+                super().append(Entity(name=entity))
         elif isinstance(entity, QueryTemplate):
             super().append(entity)
         else:
             warn("Entity was neither an id nor a name nor an entity." +
                  " (was " + str(type(entity)) + ":\n" + str(entity) + ")")
-            # raise TypeError(
-            #     "Entity was neither an id nor a name nor an entity." +
-            #     " (was " + str(type(entity)) + "\n" + str(entity) + ")")
 
         return self
 
@@ -3040,7 +3053,7 @@ class Container(list):
 
                     if e.has_errors() is True:
                         e.is_valid = lambda: False
-                    elif e.id is None or e.id < 0:
+                    elif e.id is None or is_temporary_id(e.id):
                         e.is_valid = lambda: False
                     else:
                         e.is_valid = lambda: True
@@ -3201,17 +3214,22 @@ class Container(list):
         # match by name
 
         for local_entity in self:
+            find_by_name = local_entity.name
+            if (experimental_string_ids()
+                    and find_by_name is None):
+                find_by_name = local_entity.id  # match remotes id with local name
+
             if (sync_dict[local_entity] is None
-                    and local_entity.name is not None):
+                    and find_by_name is not None):
                 sync_remote_entities = []
 
                 for remote_entity in remote_container:
                     if (remote_entity.name is not None
-                        and (str(remote_entity.name) == str(local_entity.name)
+                        and (str(remote_entity.name) == str(find_by_name)
                              or
                              (name_case_sensitive is False and
                               str(remote_entity.name).lower() == str(
-                                  local_entity.name).lower()))
+                                  find_by_name).lower()))
                             and remote_entity not in used_remote_entities):
                         sync_remote_entities.append(remote_entity)
                         used_remote_entities.append(remote_entity)
@@ -3221,7 +3239,7 @@ class Container(list):
 
                 if unique and len(sync_remote_entities) > 1:
                     msg = "Request was not unique. Name " + \
-                        str(local_entity.name) + " was found " + \
+                        str(find_by_name) + " was found " + \
                         str(len(sync_remote_entities)) + " times."
                     local_entity.add_message(Message(description=msg, type="Error"))
 
@@ -3279,19 +3297,17 @@ class Container(list):
 
                     if references.value is None:
                         continue
-                    elif isinstance(references.value, int):
-                        is_being_referenced.add(references.value)
+                    elif hasattr(references.value, "id"):
+                        is_being_referenced.add(references.value.id)
+
                     elif is_list_datatype(references.datatype):
                         for list_item in references.value:
-                            if isinstance(list_item, int):
-                                is_being_referenced.add(list_item)
-                            else:
+                            if hasattr(list_item, "id"):
                                 is_being_referenced.add(list_item.id)
+                            else:
+                                is_being_referenced.add(list_item)
                     else:
-                        try:
-                            is_being_referenced.add(references.value.id)
-                        except AttributeError:
-                            pass
+                        is_being_referenced.add(references.value)
 
                 if hasattr(references, 'id'):
                     is_property.add(references.id)
@@ -3436,7 +3452,7 @@ class Container(list):
 
         if query is None:
             for entity in self:
-                if entity.id is not None and entity.id < 0:
+                if entity.id is not None and is_temporary_id(entity.id):
                     entity.id = None
                 entity.clear_server_messages()
 
@@ -3567,7 +3583,7 @@ class Container(list):
             flags["uniquename"] = "true"
 
         for entity in self:
-            if (entity.id is None or entity.id < 0):
+            if (entity.id is None or is_temporary_id(entity.id)):
                 ee = EntityError(
                     "You tried to update an entity without a valid id.",
                     entity)
@@ -3788,15 +3804,25 @@ class Container(list):
         tmpid = 0
 
         if entity.id is not None:
-            tmpid = min(tmpid, int(entity.id))
+            try:
+                tmpid = min(tmpid, int(entity.id))
+            except ValueError:
+                pass
 
         for p in entity.get_parents():
             if p.id is not None:
-                tmpid = min(tmpid, int(p.id))
+                try:
+                    tmpid = min(tmpid, int(p.id))
+                except ValueError:
+                    pass
 
         for p in entity.get_properties():
             if p.id is not None:
-                tmpid = min(tmpid, Container._get_smallest_tmpid(p))
+                try:
+                    tmpid = min(tmpid, int(p.id))
+                except ValueError:
+                    pass
+            tmpid = min(tmpid, Container._get_smallest_tmpid(p))
 
         return tmpid
 
diff --git a/src/caosdb/high_level_api.py b/src/caosdb/high_level_api.py
index 3509a7b6bfe7ec322f2e0d2590334c6fc6f02cf8..4f2ac797888fed17c2b1780750a91f48e87611a9 100644
--- a/src/caosdb/high_level_api.py
+++ b/src/caosdb/high_level_api.py
@@ -60,23 +60,23 @@ def standard_type_for_high_level_type(high_level_record: "CaosDBPythonEntity",
     class in the standard CaosDB API or - if return_string is True - return
     the role as a string.
     """
-    if type(high_level_record) == CaosDBPythonRecord:
+    if isinstance(high_level_record, CaosDBPythonRecord):
         if not return_string:
             return db.Record
         return "Record"
-    elif type(high_level_record) == CaosDBPythonFile:
+    elif isinstance(high_level_record, CaosDBPythonFile):
         if not return_string:
             return db.File
         return "File"
-    elif type(high_level_record) == CaosDBPythonProperty:
+    elif isinstance(high_level_record, CaosDBPythonProperty):
         if not return_string:
             return db.Property
         return "Property"
-    elif type(high_level_record) == CaosDBPythonRecordType:
+    elif isinstance(high_level_record, CaosDBPythonRecordType):
         if not return_string:
             return db.RecordType
         return "RecordType"
-    elif type(high_level_record) == CaosDBPythonEntity:
+    elif isinstance(high_level_record, CaosDBPythonEntity):
         if not return_string:
             return db.Entity
         return "Entity"
@@ -101,15 +101,15 @@ def high_level_type_for_standard_type(standard_record: db.Entity):
     if not isinstance(standard_record, db.Entity):
         raise ValueError()
     role = standard_record.role
-    if role == "Record" or type(standard_record) == db.Record:
+    if role == "Record" or isinstance(standard_record, db.Record):
         return CaosDBPythonRecord
-    elif role == "File" or type(standard_record) == db.File:
+    elif role == "File" or isinstance(standard_record, db.File):
         return CaosDBPythonFile
-    elif role == "Property" or type(standard_record) == db.Property:
+    elif role == "Property" or isinstance(standard_record, db.Property):
         return CaosDBPythonProperty
-    elif role == "RecordType" or type(standard_record) == db.RecordType:
+    elif role == "RecordType" or isinstance(standard_record, db.RecordType):
         return CaosDBPythonRecordType
-    elif role == "Entity" or type(standard_record) == db.Entity:
+    elif role == "Entity" or isinstance(standard_record, db.Entity):
         return CaosDBPythonEntity
     raise RuntimeError("Incompatible type.")
 
@@ -213,14 +213,14 @@ class CaosDBPythonEntity(object):
         """
         Getter for the file.
         """
-        if type(self) != CaosDBPythonFile:
+        if not isinstance(self, CaosDBPythonFile):
             raise RuntimeError("Please don't use the file attribute for entities"
                                " that are no files.")
         return self._file
 
     @file.setter
     def file(self, val: str):
-        if val is not None and type(self) != CaosDBPythonFile:
+        if val is not None and not isinstance(self, CaosDBPythonFile):
             raise RuntimeError("Please don't use the file attribute for entities"
                                " that are no files.")
         self._file = val
@@ -230,14 +230,14 @@ class CaosDBPythonEntity(object):
         """
         Getter for the path.
         """
-        if type(self) != CaosDBPythonFile:
+        if not isinstance(self, CaosDBPythonFile):
             raise RuntimeError("Please don't use the path attribute for entities"
                                " that are no files.")
         return self._path
 
     @path.setter
     def path(self, val: str):
-        if val is not None and type(self) != CaosDBPythonFile:
+        if val is not None and not isinstance(self, CaosDBPythonFile):
             raise RuntimeError("Please don't use the path attribute for entities"
                                " that are no files.")
         self._path = val
@@ -651,7 +651,7 @@ class CaosDBPythonEntity(object):
             if baseprop in serialization:
                 entity.__setattr__(baseprop, serialization[baseprop])
 
-        if type(entity) == CaosDBPythonFile:
+        if isinstance(entity, CaosDBPythonFile):
             entity.file = serialization["file"]
             entity.path = serialization["path"]
 
@@ -721,9 +721,11 @@ class CaosDBPythonEntity(object):
         for baseprop in ("name", "id", "description", "version"):
             val = self.__getattribute__(baseprop)
             if val is not None:
+                if baseprop == "id":
+                    val = str(val)
                 fulldict[baseprop] = val
 
-        if type(self) == CaosDBPythonFile:
+        if isinstance(self, CaosDBPythonFile):
             fulldict["file"] = self.file
             fulldict["path"] = self.path
 
diff --git a/unittests/test_add_property.py b/unittests/test_add_property.py
index 0d3183b4c0ca5517ecea68d0e49bbf335bb2a13e..6a9c56ac509c8d5fd5675e5cfc3aa1fa986ea334 100644
--- a/unittests/test_add_property.py
+++ b/unittests/test_add_property.py
@@ -116,7 +116,7 @@ def test_property_parameter_with_entity():
     concrete_property = rec.get_property("length")
     assert concrete_property is not None
     assert concrete_property.name == "length"
-    assert concrete_property.id == 512
+    assert str(concrete_property.id) == str(512)
     assert concrete_property.description == "This is the length of something."
     assert concrete_property.unit == "m"
     assert concrete_property.datatype == db.DOUBLE
@@ -138,7 +138,7 @@ def test_property_parameter_with_entity_and_value():
     concrete_property = rec.get_property("length")
     assert concrete_property is not None
     assert concrete_property.name == "length"
-    assert concrete_property.id == 512
+    assert str(concrete_property.id) == str(512)
     assert concrete_property.description == "This is the length of something."
     assert concrete_property.unit == "m"
     assert concrete_property.value == 3.14
@@ -154,7 +154,7 @@ def test_property_parameter_with_id():
     assert 1 == len(rec.get_properties())
     concrete_property = rec.get_property(512)
     assert concrete_property is not None
-    assert concrete_property.id == 512
+    assert str(concrete_property.id) == str(512)
 
 
 def test_property_parameter_with_id_and_value():
@@ -165,7 +165,7 @@ def test_property_parameter_with_id_and_value():
     assert 1 == len(rec.get_properties())
     concrete_property = rec.get_property(512)
     assert concrete_property is not None
-    assert concrete_property.id == 512
+    assert str(concrete_property.id) == str(512)
     assert concrete_property.value == 3.14
 
 
@@ -177,7 +177,7 @@ def test_datatype():
     assert 1 == len(rec.get_properties())
     concrete_property = rec.get_property(512)
     assert concrete_property is not None
-    assert concrete_property.id == 512
+    assert str(concrete_property.id) == str(512)
     assert concrete_property.value == 3.14
 
 
@@ -196,7 +196,7 @@ def test_property_parameter_with_entity_and_datatype():
     concrete_property = rec.get_property("length")
     assert concrete_property is not None
     assert concrete_property.name == "length"
-    assert concrete_property.id == 512
+    assert str(concrete_property.id) == str(512)
     assert concrete_property.description == "This is the length of something."
     assert concrete_property.unit == "m"
     assert concrete_property.value == 300
@@ -262,7 +262,7 @@ def test_add_list_of_entitities():
 
     i = 0
     for e in rec.get_property("listOfEntities").value:
-        assert i == e.id
+        assert str(i) == str(e.id)
         i += 1
 
 
diff --git a/unittests/test_apiutils.py b/unittests/test_apiutils.py
index bda381cf6427377194e272dfa14b83399b6f012f..fa818df3982735c3c9f8e99d3a333337a72a99ce 100644
--- a/unittests/test_apiutils.py
+++ b/unittests/test_apiutils.py
@@ -44,13 +44,13 @@ def test_apply_to_ids():
     rec.add_property(p)
 
     def invert(id_):
-        return id_ * -1
+        return int(id_) * -1
     apply_to_ids([rec], invert)
 
     assert invert(3456) == -3456
-    assert rec.parents[0].id == -3456
-    assert rec.properties[0].id == -23345
-    assert rec.id == -23
+    assert str(rec.parents[0].id) == str(-3456)
+    assert str(rec.properties[0].id) == str(-23345)
+    assert str(rec.id) == str(-23)
 
 
 def test_id_query():
@@ -65,7 +65,7 @@ def test_resolve_reference():
 
     prop = db.Property(id=1, datatype=db.REFERENCE, value=100)
     prop.is_valid = lambda: True
-    items = [200, 300, 400]
+    items = ["200", "300", "400"]
     prop_list = db.Property(datatype=db.LIST(db.REFERENCE),
                             value=items)
     prop_list2 = db.Property(datatype=db.LIST(db.REFERENCE),
@@ -73,18 +73,18 @@ def test_resolve_reference():
     resolve_reference(prop)
     resolve_reference(prop_list)
     resolve_reference(prop_list2)
-    assert prop.value.id == 100
+    assert str(prop.value.id) == str(100)
     assert isinstance(prop.value, db.Entity)
 
     prop_list_ids = []
 
     for i in prop_list.value:
-        prop_list_ids.append(i.id)
+        prop_list_ids.append(str(i.id))
         assert isinstance(i, db.Entity)
     assert prop_list_ids == items
 
     for i in prop_list2.value:
-        assert i.id == 500
+        assert str(i.id) == str(500)
         assert isinstance(i, db.Entity)
 
     no_reference = db.Property(id=5000, datatype=db.INTEGER, value=2)
@@ -206,8 +206,8 @@ def test_compare_special_properties():
             assert diff_r1[key] == "bla 1"
             assert diff_r2[key] == "bla test"
         else:
-            assert diff_r1[key] == 1
-            assert diff_r2[key] == 2
+            assert str(diff_r1[key]) == str(1)
+            assert str(diff_r2[key]) == str(2)
         assert len(diff_r1["properties"]) == 0
         assert len(diff_r2["properties"]) == 0
 
@@ -301,7 +301,7 @@ def test_merge_entities():
 
 def test_merge_bug_conflict():
     r = db.Record()
-    r.add_property(name="C", value=4)
+    r.add_property(name="C", value="4")
     r2 = db.Record()
     r2.add_property(name="C", value=4, datatype="TEXT")
     merge_entities(r, r2)
diff --git a/unittests/test_cached.py b/unittests/test_cached.py
index ce302d671d6077aed7d8457e70da2076ebe65d50..bc9e1804f871edb7cf070b91b83e607b1696f89f 100644
--- a/unittests/test_cached.py
+++ b/unittests/test_cached.py
@@ -52,7 +52,7 @@ def mocked_name_query(name):
 
 def mocked_id_query(eid):
     # copy the object, because Entities would normally be created from XML response
-    return deepcopy([el for el in DUMMY_SERVER_CONTENT if el.id == eid][0])
+    return deepcopy([el for el in DUMMY_SERVER_CONTENT if str(el.id) == str(eid)][0])
 
 
 def mocked_path_query(path):
@@ -78,7 +78,7 @@ def test_get_by_name(mocked_get_by_name):
     mocked_get_by_name.side_effect = mocked_name_query
     # first call; not in cache -> mocked_execute is touched
     a = cached_get_entity_by(name='a')
-    assert a.id == 101
+    assert str(a.id) == str(101)
     assert mocked_get_by_name.call_count == 1
     # second call; in cache -> mocked_execute is NOT touched (count is still 1)
     b = cached_get_entity_by(name='a')
@@ -98,13 +98,13 @@ def test_get_by_name(mocked_get_by_name):
     assert cache_info().currsize == 2
     # we can retrieve the inserted element
     lol = cached_get_entity_by(name='lol')
-    assert lol.id == 10001
+    assert str(lol.id) == str(10001)
     # this did not touch the mocked function
     assert mocked_get_by_name.call_count == 2
     # make sure normal retrieval still works (count +1)
     c = cached_get_entity_by(name='c')
     assert mocked_get_by_name.call_count == 3
-    assert c.id == 103
+    assert str(c.id) == str(103)
 
 
 @patch("caosdb.utils.get_entity.get_entity_by_id")
@@ -112,7 +112,7 @@ def test_get_by_id(mocked_get_by_id):
     mocked_get_by_id.side_effect = mocked_id_query
     # first call; not in cache -> mocked_execute is touched
     b = cached_get_entity_by(eid=102)
-    assert b.id == 102
+    assert str(b.id) == str(102)
     assert b.name == 'b'
     assert mocked_get_by_id.call_count == 1
     # second call; in cache -> mocked_execute is NOT touched (count is still 1)
@@ -147,7 +147,7 @@ def test_get_by_path(mocked_get_by_path):
     mocked_get_by_path.side_effect = mocked_path_query
     # first call; not in cache -> mocked_execute is touched
     b = cached_get_entity_by(path='p')
-    assert b.id == 104
+    assert str(b.id) == str(104)
     assert mocked_get_by_path.call_count == 1
     # second call; in cache -> mocked_execute is NOT touched (count is still 1)
     a = cached_get_entity_by(path='p')
@@ -167,13 +167,13 @@ def test_get_by_path(mocked_get_by_path):
     assert cache_info().currsize == 2
     # we can retrieve the inserted element
     lol = cached_get_entity_by(path='lol')
-    assert lol.id == 10001
+    assert str(lol.id) == str(10001)
     # this did not touch the mocked function
     assert mocked_get_by_path.call_count == 2
     # make sure normal retrieval still works (count +1)
     c = cached_get_entity_by(path='pp')
     assert mocked_get_by_path.call_count == 3
-    assert c.id == 105
+    assert str(c.id) == str(105)
 
 
 @patch("caosdb.cached.execute_query")
@@ -199,7 +199,7 @@ def test_get_by_query(mocked_query):
     # Existent entity
     a = cached_get_entity_by(query='a')
     assert a is not None
-    assert a.id == 101
+    assert str(a.id) == str(101)
     assert cache_info().currsize == 2
     assert cache_info().hits == 1
     assert cache_info().misses == 2
@@ -234,13 +234,13 @@ def test_cached_query(mocked_query):
     assert cache_info().currsize == 2
     # we can retrieve the inserted element
     lol = cached_query('lol')
-    assert lol[0].id == 10001
+    assert str(lol[0].id) == str(10001)
     # this did not touch the mocked function
     assert mocked_query.call_count == 2
     # make sure normal retrieval still works (count +1)
     c = cached_query('a')
     assert mocked_query.call_count == 3
-    assert c[0].id == 101
+    assert str(c[0].id) == str(101)
 
 
 @patch("caosdb.utils.get_entity.get_entity_by_name")
diff --git a/unittests/test_container.py b/unittests/test_container.py
index 0ac4be44826825aa3302119c8bca08f335ab68d3..15972b95739d57d09f5e8fb4513555b7ea0d4cbb 100644
--- a/unittests/test_container.py
+++ b/unittests/test_container.py
@@ -26,6 +26,7 @@
 from __future__ import absolute_import
 
 import caosdb as db
+from caosdb.common.models import entity_id
 
 
 def test_get_property_values():
@@ -126,7 +127,7 @@ def test_container_dependencies_for_deletion():
         record_with_property_which_is_not_a_record
     ])
     assert (db.Container()._test_dependencies_in_container(container)
-            == {2002, 1005, 1007})
+            == {entity_id(2002), entity_id(1005), entity_id(1007)})
 
 
 def test_container_dependencies_for_deletion_with_lists():
@@ -143,4 +144,4 @@ def test_container_dependencies_for_deletion_with_lists():
     container = db.Container()
     container.extend([record_with_list, record_referenced])
 
-    assert db.Container()._test_dependencies_in_container(container) == {2001}
+    assert db.Container()._test_dependencies_in_container(container) == {entity_id(2001)}
diff --git a/unittests/test_datatype.py b/unittests/test_datatype.py
index 9b3c6267fb018e2cd3085dea568d7396c4549ac8..a22dbd06441bb665d887667a19cff9d80afcce90 100644
--- a/unittests/test_datatype.py
+++ b/unittests/test_datatype.py
@@ -21,7 +21,7 @@
 from pytest import raises
 import caosdb as db
 from caosdb.common import datatype
-from caosdb.common.models import _parse_value
+from caosdb.common.models import _parse_value, entity_id
 
 
 def test_list():
@@ -72,8 +72,8 @@ def test_parsing_of_references():
     assert _parse_value(dtype, "Anna Lytik") == "Anna Lytik"
     assert _parse_value(None, "Anna Lytik") == "Anna Lytik"
     assert _parse_value(dtype, "2345@sdfg") == "2345@sdfg"
-    assert _parse_value(dtype, "2345") == 2345
-    assert _parse_value(dtype, 2345) == 2345
+    assert _parse_value(dtype, "2345") == entity_id(2345)
+    assert _parse_value(dtype, 2345) == entity_id(2345)
 
     entity = db.Record(name="bla")
     assert id(_parse_value(dtype, entity)) == id(entity)
@@ -82,8 +82,8 @@ def test_parsing_of_references():
     assert _parse_value(dtype, "Anna Lytik") == "Anna Lytik"
     assert _parse_value(None, "Anna Lytik") == "Anna Lytik"
     assert _parse_value(dtype, "2345@sdfg") == "2345@sdfg"
-    assert _parse_value(dtype, "2345") == 2345
-    assert _parse_value(dtype, 2345) == 2345
+    assert _parse_value(dtype, "2345") == entity_id(2345)
+    assert _parse_value(dtype, 2345) == entity_id(2345)
 
     entity = db.Record(name="bla")
     assert id(_parse_value(dtype, entity)) == id(entity)
diff --git a/unittests/test_high_level_api.py b/unittests/test_high_level_api.py
index ea5e635eadaa849480de5f3ece10b813a538a1b0..18f409f59721e15f5047f21b458766cf96d680b6 100644
--- a/unittests/test_high_level_api.py
+++ b/unittests/test_high_level_api.py
@@ -165,7 +165,7 @@ def test_convert_with_references():
     # Parent does not automatically lead to a datatype:
     assert obj.get_property_metadata("ref").datatype == "bla"
     assert isinstance(obj.ref, CaosDBPythonUnresolvedReference)
-    assert obj.ref.id == 27
+    assert str(obj.ref.id) == str(27)
 
 
 def test_resolve_references():
@@ -187,19 +187,19 @@ def test_resolve_references():
     # Nothing is going to be resolved:
     obj.resolve_references(False, db.Container())
     assert isinstance(obj.ref, CaosDBPythonUnresolvedReference)
-    assert obj.ref.id == 27
+    assert str(obj.ref.id) == str(27)
     assert obj.ref_false == 27
 
     # deep == True does not help:
     obj.resolve_references(True, db.Container())
     assert isinstance(obj.ref, CaosDBPythonUnresolvedReference)
-    assert obj.ref.id == 27
+    assert str(obj.ref.id) == str(27)
 
     # But adding the reference container will do:
     obj.resolve_references(False, references)
     assert not isinstance(obj.ref, CaosDBPythonUnresolvedReference)
     assert isinstance(obj.ref, CaosDBPythonRecord)
-    assert obj.ref.id == 27
+    assert str(obj.ref.id) == str(27)
     assert obj.ref.a == 57
     # Datatypes will not automatically be set:
     assert obj.ref.get_property_metadata("a").datatype is None
@@ -214,19 +214,19 @@ def test_resolve_references():
     obj.resolve_references(False, references)
     assert not isinstance(obj.ref, CaosDBPythonUnresolvedReference)
     assert isinstance(obj.ref.ref, CaosDBPythonUnresolvedReference)
-    assert obj.ref.ref.id == 225
+    assert str(obj.ref.ref.id) == str(225)
 
     # Will not help, because ref2 is missing in container:
     obj.resolve_references(True, references)
     assert not isinstance(obj.ref, CaosDBPythonUnresolvedReference)
     assert isinstance(obj.ref.ref, CaosDBPythonUnresolvedReference)
-    assert obj.ref.ref.id == 225
+    assert str(obj.ref.ref.id) == str(225)
 
     references.append(ref2)
     obj.resolve_references(False, references)
     assert not isinstance(obj.ref, CaosDBPythonUnresolvedReference)
     assert isinstance(obj.ref.ref, CaosDBPythonUnresolvedReference)
-    assert obj.ref.ref.id == 225
+    assert str(obj.ref.ref.id) == str(225)
 
     obj.resolve_references(True, references)
     assert not isinstance(obj.ref, CaosDBPythonUnresolvedReference)
@@ -279,7 +279,7 @@ def test_base_properties():
                    importance="RECOMMENDED", description="description")
     obj = convert_to_python_object(r)
     assert obj.name == "test"
-    assert obj.id == 5
+    assert str(obj.id) == str(5)
     assert obj.description == "ok"
     metadata = obj.get_property_metadata("v")
     assert metadata.id is None
@@ -290,7 +290,7 @@ def test_base_properties():
 
     rconv = convert_to_entity(obj)
     assert rconv.name == "test"
-    assert rconv.id == 5
+    assert str(rconv.id) == str(5)
     assert rconv.description == "ok"
     prop = rconv.get_property("v")
     assert prop.value == 15
@@ -328,7 +328,7 @@ def test_serialization():
 
     obj = convert_to_python_object(r)
     text = str(obj)
-    teststrs = ["description: ok", "id: 5", "datatype: INTEGER",
+    teststrs = ["description: ok", "id: '5'", "datatype: INTEGER",
                 "importance: RECOMMENDED", "unit: kpx", "name: test", "v: 15"]
     for teststr in teststrs:
         assert teststr in text
@@ -385,21 +385,21 @@ def test_files():
     rec = db.Record()
     rec.add_property(name="testfile", value=2, datatype=db.FILE)
     obj = convert_to_python_object(rec)
-    assert type(obj.testfile) == CaosDBPythonUnresolvedReference
-    assert obj.testfile.id == 2
+    assert isinstance(obj.testfile, CaosDBPythonUnresolvedReference)
+    assert str(obj.testfile.id) == "2"
     assert obj.get_property_metadata("testfile").datatype == db.FILE
 
     # without resolving references:
     rconv = convert_to_entity(obj)
     p = rconv.get_property("testfile")
-    assert p.value == 2
+    assert str(p.value) == "2"
     assert p.datatype == db.FILE
 
     # with previously resolved reference (should not work here, because id is missing):
     obj.resolve_references(True, db.Container().extend(r))
     rconv = convert_to_entity(obj)
     p = rconv.get_property("testfile")
-    assert p.value == 2
+    assert str(p.value) == "2"
     assert p.datatype == db.FILE
 
     # this time it must work:
@@ -407,7 +407,7 @@ def test_files():
     obj.resolve_references(True, db.Container().extend(r))
     rconv = convert_to_entity(obj)
     p = rconv.get_property("testfile")
-    assert type(p.value) == db.File
+    assert isinstance(p.value, db.File)
     assert p.datatype == db.FILE
     assert p.value.file == "/local/path/test.dat"
     assert p.value.path == "test.dat"
@@ -436,7 +436,7 @@ def test_list_types():
     assert get_list_datatype(r.get_property("a").datatype) is None
 
     obj = convert_to_python_object(r)
-    assert type(obj.a) == list
+    assert isinstance(obj.a, list)
     assert len(obj.a) == 3
     assert 4 in obj.a
     assert obj.get_property_metadata("a").datatype is None
@@ -449,7 +449,7 @@ def test_list_types():
     r.get_property("a").datatype = db.LIST(db.INTEGER)
     assert r.get_property("a").datatype == "LIST<INTEGER>"
     obj = convert_to_python_object(r)
-    assert type(obj.a) == list
+    assert isinstance(obj.a, list)
     assert len(obj.a) == 3
     assert 4 in obj.a
     assert obj.get_property_metadata("a").datatype == "LIST<INTEGER>"
@@ -463,22 +463,22 @@ def test_list_types():
     r = db.Record()
     r.add_property(name="a", value=[1, 2, 4], datatype="LIST<TestReference>")
     obj = convert_to_python_object(r)
-    assert type(obj.a) == list
+    assert isinstance(obj.a, list)
     assert len(obj.a) == 3
     assert obj.get_property_metadata("a").datatype == "LIST<TestReference>"
     for i in range(3):
-        assert type(obj.a[i]) == CaosDBPythonUnresolvedReference
+        assert isinstance(obj.a[i], CaosDBPythonUnresolvedReference)
     assert obj.a == [CaosDBPythonUnresolvedReference(id=i) for i in [1, 2, 4]]
 
     # Try resolving:
 
     # Should not work:
     obj.resolve_references(False, db.Container())
-    assert type(obj.a) == list
+    assert isinstance(obj.a, list)
     assert len(obj.a) == 3
     assert obj.get_property_metadata("a").datatype == "LIST<TestReference>"
     for i in range(3):
-        assert type(obj.a[i]) == CaosDBPythonUnresolvedReference
+        assert isinstance(obj.a[i], CaosDBPythonUnresolvedReference)
     assert obj.a == [CaosDBPythonUnresolvedReference(id=i) for i in [1, 2, 4]]
 
     references = db.Container()
@@ -488,11 +488,11 @@ def test_list_types():
         references.append(ref)
 
     obj.resolve_references(False, references)
-    assert type(obj.a) == list
+    assert isinstance(obj.a, list)
     assert len(obj.a) == 3
     assert obj.get_property_metadata("a").datatype == "LIST<TestReference>"
     for i in range(3):
-        assert type(obj.a[i]) == CaosDBPythonRecord
+        assert isinstance(obj.a[i], CaosDBPythonRecord)
 
     assert obj.a[0].val == "1 bla"
 
@@ -506,7 +506,7 @@ def test_list_types():
     r.add_property(name="a", value=[r2, r3])
 
     obj = convert_to_python_object(r)
-    assert type(obj.a) == list
+    assert isinstance(obj.a, list)
     assert len(obj.a) == 2
     assert obj.a[0].a == 4
     assert obj.a[1].b == 8
@@ -559,7 +559,7 @@ def test_deserialization():
     obj_des = CaosDBPythonEntity.deserialize(serial)
 
     assert obj_des.name == "test"
-    assert obj_des.id == 17
+    assert str(obj_des.id) == "17"
     assert obj_des.has_parent(CaosDBPythonUnresolvedParent(name="bla"))
     print(obj)
     print(obj_des)
@@ -622,9 +622,9 @@ def get_record_container():
 def test_recursion(get_record_container):
     r = convert_to_python_object(get_record_container[0])
     r.resolve_references(r, get_record_container)
-    assert r.id == 109
-    assert r.sources[0].id == 109
-    assert r.sources[0].sources[0].id == 109
+    assert str(r.id) == "109"
+    assert str(r.sources[0].id) == "109"
+    assert str(r.sources[0].sources[0].id) == "109"
     assert "&id001" in str(r)
     assert "*id001" in str(r)
 
diff --git a/unittests/test_property.py b/unittests/test_property.py
index 84f89b5a959192d7831e1bb3eab3a441912afe7e..0e1b4b7582d225d584f7026c6f5bff289b6412af 100644
--- a/unittests/test_property.py
+++ b/unittests/test_property.py
@@ -71,7 +71,7 @@ def test_null_empty_text_value_5():
 
 def test_list_of_references_with_null():
     assert testrecord.get_property("MultiRecRecording").value[0] is None
-    assert testrecord.get_property("MultiRecRecording").value[1] == 170651
+    assert str(testrecord.get_property("MultiRecRecording").value[1]) == "170651"
 
 
 def test_role():
@@ -96,13 +96,13 @@ def test_selected_reference_list():
 
 def test_is_reference():
     PROPS = {
-        10:  db.INTEGER,
-        20:  db.REFERENCE,
-        30:  "SomeRT",
+        "10":  db.INTEGER,
+        "20":  db.REFERENCE,
+        "30":  "SomeRT",
     }
 
     def dummy_retrieve(self):
-        self.datatype = PROPS[self.id]
+        self.datatype = PROPS[str(self.id)]
         self.is_valid = lambda: True
     # replace retrieve function by dummy
     real_retrieve = Entity.retrieve