diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6255ff1c0286f518b9dbd333bd3f61dd690e5cb4..5aa592990ce2b80b9fde674959246c38c4278bb2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added ###
 
+* is_reference function for Properties
+
 ### Changed ###
 
 ### Deprecated ###
diff --git a/src/caosdb/common/models.py b/src/caosdb/common/models.py
index 0142b04477c600bade9603c1de59e850afed931e..57b07bd6f83cf2dd4d0523a70308ee189a96a995 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
@@ -1504,6 +1505,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):
 
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