diff --git a/src/caosdb/__init__.py b/src/caosdb/__init__.py
index 78a17aef9703b3050b78904c0b50357fcbf3291c..45303cc275042b4eb83ab37f2fd67ce077fa0561 100644
--- a/src/caosdb/__init__.py
+++ b/src/caosdb/__init__.py
@@ -46,7 +46,7 @@ from caosdb.common.models import (ACL, ALL, FIX, NONE, OBLIGATORY, RECOMMENDED,
                                   Query, QueryTemplate, Record, RecordType,
                                   delete, execute_query, get_global_acl,
                                   get_known_permissions, raise_errors,
-                                  Directory)
+                                  Directory, Link)
 from caosdb.configuration import _read_config_files, configure, get_config
 from caosdb.connection.connection import configure_connection, get_connection
 from caosdb.exceptions import *
diff --git a/src/caosdb/common/models.py b/src/caosdb/common/models.py
index 4bd5e5a587e2d14f1ab8a78e40fb901232809e2a..4b4e8181adfc023a349161e16bb2bc68638c8dd0 100644
--- a/src/caosdb/common/models.py
+++ b/src/caosdb/common/models.py
@@ -115,6 +115,7 @@ class Entity(object):
         self.parents = _Parents()
         self.path = None
         self.file = None
+        self.link_target = None
         self.unit = None
         self.acl = None
         self.permissions = None
@@ -297,6 +298,17 @@ class Entity(object):
 
         return self._wrapped_entity.path
 
+    @link_target.setter
+    def link_target(self, new_link_target):
+        self.__link_target = new_link_target
+
+    @property
+    def link_target(self):
+        if self.__link_target is not None or self._wrapped_entity is None:
+            return self.__link_target
+
+        return self._wrapped_entity.link_target
+
     @path.setter
     def path(self, new_path):
         self.__path = new_path
@@ -1063,6 +1075,9 @@ class Entity(object):
         if self.file is not None and local_serialization:
             xml.set("file", self.file)
 
+        if self.link_target is not None:
+            xml.set("linktarget", self.link_target)
+
         if self.checksum is not None:
             xml.set("checksum", self.checksum)
 
@@ -1817,6 +1832,38 @@ class Record(Entity):
         return Entity.to_xml(self, xml, add_properties=ALL)
 
 
+class Link(Entity):
+    """This class represents CaosDB's link entities."""
+
+    def __init__(self, name=None, id=None, description=None, path=None, target=None)
+        Record.__init__(self, id=id, name=name, description=description)
+        self.role = "Link"
+        self.datatype = None
+        self.link_target = target
+
+        # location in the fileserver
+        self.path = path
+
+    def to_xml(self, xml=None, add_properties=ALL, local_serialization=False):
+        """Convert this Link to an xml element.
+
+        @return: xml element
+        """
+
+        if xml is None:
+            xml = etree.Element("Link")
+
+        return Entity.to_xml(self, xml=xml, add_properties=add_properties,
+                             local_serialization=local_serialization)
+
+    def add_property(self, property=None, id=None, name=None, description=None, datatype=None,
+                     value=None, unit=None, importance=FIX, inheritance=FIX):
+
+        return super().add_property(
+            property=property, id=id, name=name, description=description, datatype=datatype,
+            value=value, unit=unit, importance=importance, inheritance=inheritance)
+
+
 class Directory(Record):
     """This class represents CaosDB's directory entities."""
 
@@ -2510,6 +2557,7 @@ def _basic_sync(e_local, e_remote):
     e_local.name = e_remote.name
     e_local.description = e_remote.description
     e_local.path = e_remote.path
+    e_local.link_target = e_remote.link_target
     e_local._checksum = e_remote._checksum
     e_local._size = e_remote._size
     e_local.datatype = e_remote.datatype
@@ -4415,6 +4463,7 @@ def _parse_single_xml_element(elem):
         'property': Property,
         'file': File,
         'directory': Directory,
+        'link': Link,
         'parent': Parent,
         'entity': Entity}