diff --git a/CHANGELOG.md b/CHANGELOG.md
index 22ce0c27bc196c81f1aa10f132b2d62b50f1cc63..7bebc70ca8ade4d56695dca9e9c47379dcd90758 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added
 
+- Support for deeply nested selectors in SELECT queries.
 - One-time Authentication Tokens for login without credentials and login with
   particular permissions and roles for the course of the session.
 - `Entity/names` resource for retrieving all known entity names.
@@ -23,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
   [README.md](misc/move_files/README.md).
 - LDAP server may now be given and may be different from LDAP domain. See
   `misc/pam_authentication/ldap.conf`
+- #47 - Sub-properties can now be queried, such as in `SELECT window.width FROM house`.
+
 
 ### Changed
 
diff --git a/caosdb-webui b/caosdb-webui
index 136582641fb1b675d9630b4eacea54fbf7765eea..66026626089e2b514538510a1a6744868f46b661 160000
--- a/caosdb-webui
+++ b/caosdb-webui
@@ -1 +1 @@
-Subproject commit 136582641fb1b675d9630b4eacea54fbf7765eea
+Subproject commit 66026626089e2b514538510a1a6744868f46b661
diff --git a/src/main/java/caosdb/server/database/backend/transaction/RetrieveFullEntity.java b/src/main/java/caosdb/server/database/backend/transaction/RetrieveFullEntity.java
index 7ac8c1592e0cb275e60008532cdabb33919369a9..a1817767650175f604286a29ea82b5387a4dc2d6 100644
--- a/src/main/java/caosdb/server/database/backend/transaction/RetrieveFullEntity.java
+++ b/src/main/java/caosdb/server/database/backend/transaction/RetrieveFullEntity.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -23,12 +25,32 @@
 package caosdb.server.database.backend.transaction;
 
 import caosdb.server.database.BackendTransaction;
+import caosdb.server.datatype.ReferenceDatatype;
+import caosdb.server.datatype.ReferenceValue;
 import caosdb.server.entity.EntityInterface;
+import caosdb.server.entity.Message;
 import caosdb.server.entity.RetrieveEntity;
 import caosdb.server.entity.Role;
 import caosdb.server.entity.container.Container;
+import caosdb.server.entity.wrapper.Property;
+import caosdb.server.query.Query;
+import caosdb.server.query.Query.Selection;
 import caosdb.server.utils.EntityStatus;
+import java.util.LinkedList;
+import java.util.List;
 
+/**
+ * Retrieve the full entity from the backend - with all parents, properties, file properties and so
+ * on.
+ *
+ * <p>TODO: This class should rather be called FullEntityRetrieval or FullEntityRetrieveTransaction.
+ *
+ * <p>When the entity which is to be retrieved has a defined list of {@link Query.Selection} which
+ * select properties from referenced entities, the referenced entities are retrieved as well.
+ * Otherwise, only the referenced id is retrieved and the entity stays rather flat.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class RetrieveFullEntity extends BackendTransaction {
 
   private final Container<? extends EntityInterface> container;
@@ -49,22 +71,106 @@ public class RetrieveFullEntity extends BackendTransaction {
 
   @Override
   public void execute() {
-    for (final EntityInterface e : this.container) {
+    retrieveFullEntitiesInContainer(this.container);
+  }
+
+  /**
+   * Retrieve the entities in the container.
+   *
+   * @param container
+   */
+  public void retrieveFullEntitiesInContainer(Container<? extends EntityInterface> container) {
+    for (final EntityInterface e : container) {
       if (e.hasId() && e.getId() > 0 && e.getEntityStatus() == EntityStatus.QUALIFIED) {
+        retrieveFullEntity(e, e.getSelections());
+      }
+    }
+  }
 
-        execute(new RetrieveSparseEntity(e));
-        if (e.getEntityStatus() == EntityStatus.VALID) {
-          if (e.getRole() == Role.QueryTemplate) {
-            execute(new RetrieveQueryTemplateDefinition(e));
-          }
-          execute(new RetrieveParents(e));
+  /**
+   * Retrieve a single full entity.
+   *
+   * <p>If the selections are not empty, retrieve the referenced entities matching the 'selections'
+   * as well.
+   *
+   * <p>This method is called recursively during the retrieval of the referenced entities.
+   *
+   * @param e The entity.
+   * @param selections
+   */
+  public void retrieveFullEntity(EntityInterface e, List<Selection> selections) {
+    execute(new RetrieveSparseEntity(e));
+
+    if (e.getEntityStatus() == EntityStatus.VALID) {
+      if (e.getRole() == Role.QueryTemplate) {
+        execute(new RetrieveQueryTemplateDefinition(e));
+      }
+      execute(new RetrieveParents(e));
+      execute(new RetrieveProperties(e));
 
-          execute(new RetrieveProperties(e));
+      // recursion! retrieveSubEntities calls retrieveFull sometimes, but with reduced selectors.
+      if (selections != null && !selections.isEmpty()) {
+        retrieveSubEntities(e, selections);
+      }
+    }
+  }
+
+  /**
+   * Retrieve the Entities which match the selections and are referenced by the Entity 'e'.
+   *
+   * @param e
+   * @param selections
+   */
+  public void retrieveSubEntities(EntityInterface e, List<Selection> selections) {
+    for (final Selection s : selections) {
+      if (s.getSubselection() != null) {
+
+        String propertyName = s.getSelector();
+
+        // Find matching (i.e. referencing) Properties
+        for (Property p : e.getProperties()) {
+          // get reference properties by name.
+          if (propertyName.equalsIgnoreCase(p.getName())
+              && p.getDatatype() instanceof ReferenceDatatype) {
+            if (p.getValue() != null) {
+              try {
+                p.parseValue();
+              } catch (Message m) {
+                p.addError(m);
+              }
+
+              ReferenceValue value = (ReferenceValue) p.getValue();
+              RetrieveEntity ref = new RetrieveEntity(value.getId());
+              // recursion!  (Only for the matching selections)
+              retrieveFullEntity(ref, getSubSelects(selections, propertyName));
+              value.setEntity(ref);
+            }
+          }
         }
       }
     }
   }
 
+  /**
+   * Return all non-null subselects of those selections which match the given select String.
+   *
+   * <p>Effectively, this reduces the depth of the selections by one (and drops non-matching
+   * selections).
+   *
+   * @param selections
+   * @param select
+   * @return A new list of Selections.
+   */
+  public List<Selection> getSubSelects(List<Selection> selections, String select) {
+    List<Selection> result = new LinkedList<>();
+    for (Selection s : selections) {
+      if (s.getSelector().equalsIgnoreCase(select) && s.getSubselection() != null) {
+        result.add(s.getSubselection());
+      }
+    }
+    return result;
+  }
+
   public Container<? extends EntityInterface> getContainer() {
     return container;
   }
diff --git a/src/main/java/caosdb/server/entity/Entity.java b/src/main/java/caosdb/server/entity/Entity.java
index 5c997d7ff8f9f98191ba768c82569a79ca056cf2..7fed351c51373e0cdb6aca9fe531c9699c2f9703 100644
--- a/src/main/java/caosdb/server/entity/Entity.java
+++ b/src/main/java/caosdb/server/entity/Entity.java
@@ -521,6 +521,7 @@ public class Entity extends AbstractObservable implements EntityInterface {
     }
   }
 
+  // Strategy to convert this Entity to an XML element.
   private ToElementStrategy toElementStrategy = null;
 
   @Override
@@ -535,7 +536,12 @@ public class Entity extends AbstractObservable implements EntityInterface {
 
   @Override
   public final void addToElement(final Element element) {
-    getToElementStrategy().addToElement(this, element, new SetFieldStrategy(getSelections()));
+    addToElement(element, new SetFieldStrategy(getSelections()));
+  }
+
+  @Override
+  public void addToElement(Element element, SetFieldStrategy strategy) {
+    getToElementStrategy().addToElement(this, element, strategy);
   }
 
   /**
diff --git a/src/main/java/caosdb/server/entity/EntityInterface.java b/src/main/java/caosdb/server/entity/EntityInterface.java
index 21ed5cd85234bd633914302ce2982b2b6f4f9a66..20aa57a5b3f64ae5794d01235049c12740a0419b 100644
--- a/src/main/java/caosdb/server/entity/EntityInterface.java
+++ b/src/main/java/caosdb/server/entity/EntityInterface.java
@@ -31,6 +31,7 @@ import caosdb.server.entity.container.PropertyContainer;
 import caosdb.server.entity.wrapper.Domain;
 import caosdb.server.entity.wrapper.Parent;
 import caosdb.server.entity.wrapper.Property;
+import caosdb.server.entity.xml.SetFieldStrategy;
 import caosdb.server.entity.xml.ToElementable;
 import caosdb.server.jobs.JobTarget;
 import caosdb.server.permissions.EntityACL;
@@ -40,6 +41,7 @@ import caosdb.unit.Unit;
 import java.util.List;
 import org.apache.shiro.authz.Permission;
 import org.apache.shiro.subject.Subject;
+import org.jdom2.Element;
 
 public interface EntityInterface
     extends JobTarget, Observable, ToElementable, WriteEntity, TransactionEntity {
@@ -182,4 +184,6 @@ public interface EntityInterface
   public abstract String getQueryTemplateDefinition();
 
   public abstract void setQueryTemplateDefinition(String query);
+
+  public abstract void addToElement(Element element, SetFieldStrategy strategy);
 }
diff --git a/src/main/java/caosdb/server/entity/container/Container.java b/src/main/java/caosdb/server/entity/container/Container.java
index 9ab0415d8c4ccc8767814eaa46a8cacfe74d594a..de20b6a3965fc4fead82612193d061e075d5217d 100644
--- a/src/main/java/caosdb/server/entity/container/Container.java
+++ b/src/main/java/caosdb/server/entity/container/Container.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -27,5 +29,17 @@ import java.util.ArrayList;
 
 public class Container<T extends EntityInterface> extends ArrayList<T> {
 
-  private static final long serialVersionUID = 3476714088253567549L;
+  private static final long serialVersionUID = 8519435849678175750L;
+
+  /**
+   * Return the entity with the matching id, if it can be found inside this Container, else null.
+   */
+  public T getEntityById(final Integer id) {
+    for (final T e : this) {
+      if (e.hasId() && e.getId().equals(id)) {
+        return e;
+      }
+    }
+    return null;
+  }
 }
diff --git a/src/main/java/caosdb/server/entity/container/PropertyContainer.java b/src/main/java/caosdb/server/entity/container/PropertyContainer.java
index a80e2bfccea9f4b9c5cbe17fc32f9dd20b74c995..80cf816156c0d4d81bca1e5b0e0de19c38fcb032 100644
--- a/src/main/java/caosdb/server/entity/container/PropertyContainer.java
+++ b/src/main/java/caosdb/server/entity/container/PropertyContainer.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -50,6 +52,7 @@ public class PropertyContainer extends Container<Property> {
     this.s = new PropertyToElementStrategy();
   }
 
+  /** Sort the properties by their pidx (Property Index). */
   public void sort() {
     Collections.sort(
         this,
@@ -64,14 +67,32 @@ public class PropertyContainer extends Container<Property> {
         });
   }
 
-  public Element addToElement(final Element element, final SetFieldStrategy setFieldStrategy) {
+  /**
+   * Add a single property to the element using the given setFieldStrategy.
+   *
+   * @param property
+   * @param element
+   * @param setFieldStrategy
+   */
+  public void addToElement(
+      EntityInterface property, Element element, SetFieldStrategy setFieldStrategy) {
+    if (setFieldStrategy.isToBeSet(property.getName())) {
+      SetFieldStrategy strategy = setFieldStrategy.forProperty(property.getName());
+      this.s.addToElement(property, element, strategy);
+    }
+  }
+
+  /**
+   * Add all properties to the element using the given setFieldStrategy.
+   *
+   * @param element
+   * @param setFieldStrategy
+   */
+  public void addToElement(final Element element, final SetFieldStrategy setFieldStrategy) {
     sort();
     for (final EntityInterface property : this) {
-      if (setFieldStrategy.isToBeSet(property.getName())) {
-        this.s.addToElement(property, element, setFieldStrategy.forProperty(property.getName()));
-      }
+      addToElement(property, element, setFieldStrategy);
     }
-    return element;
   }
 
   @Override
diff --git a/src/main/java/caosdb/server/entity/container/TransactionContainer.java b/src/main/java/caosdb/server/entity/container/TransactionContainer.java
index f0ac55fae7b57d24456728508baa7768b83a5711..f3a8a0f395838e6c8f5b2a4d8adf6f5b8627d06c 100644
--- a/src/main/java/caosdb/server/entity/container/TransactionContainer.java
+++ b/src/main/java/caosdb/server/entity/container/TransactionContainer.java
@@ -145,15 +145,6 @@ public class TransactionContainer extends Container<EntityInterface>
     }
   }
 
-  public EntityInterface getEntityById(final Integer id) {
-    for (final EntityInterface e : this) {
-      if (e.hasId() && e.getId().equals(id)) {
-        return e;
-      }
-    }
-    return null;
-  }
-
   public Subject getOwner() {
     return this.owner;
   }
diff --git a/src/main/java/caosdb/server/entity/wrapper/EntityWrapper.java b/src/main/java/caosdb/server/entity/wrapper/EntityWrapper.java
index 4d419bbfc17aee5749db70976f1a510ae468032b..056f342c6b09b8f07130e6c89013777809c567b8 100644
--- a/src/main/java/caosdb/server/entity/wrapper/EntityWrapper.java
+++ b/src/main/java/caosdb/server/entity/wrapper/EntityWrapper.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -33,6 +35,7 @@ import caosdb.server.entity.Role;
 import caosdb.server.entity.StatementStatus;
 import caosdb.server.entity.container.ParentContainer;
 import caosdb.server.entity.container.PropertyContainer;
+import caosdb.server.entity.xml.SetFieldStrategy;
 import caosdb.server.entity.xml.ToElementStrategy;
 import caosdb.server.entity.xml.ToElementable;
 import caosdb.server.permissions.EntityACL;
@@ -551,4 +554,9 @@ public class EntityWrapper implements EntityInterface {
   public boolean hasPermission(Subject subject, Permission permission) {
     return this.entity.hasPermission(subject, permission);
   }
+
+  @Override
+  public void addToElement(Element element, SetFieldStrategy strategy) {
+    this.entity.addToElement(element, strategy);
+  }
 }
diff --git a/src/main/java/caosdb/server/entity/xml/DomainToElementStrategy.java b/src/main/java/caosdb/server/entity/xml/DomainToElementStrategy.java
index 2559cfd12d7ca03344d03fa025ff2078d1bbcca0..099b51044353f3074ece5cef77a7588a658bab81 100644
--- a/src/main/java/caosdb/server/entity/xml/DomainToElementStrategy.java
+++ b/src/main/java/caosdb/server/entity/xml/DomainToElementStrategy.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -25,11 +27,22 @@ package caosdb.server.entity.xml;
 import caosdb.server.entity.EntityInterface;
 import org.jdom2.Element;
 
-public class DomainToElementStrategy implements ToElementStrategy {
+/**
+ * Generates a JDOM (XML) representation of an entity with role "Domain".
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public class DomainToElementStrategy extends EntityToElementStrategy {
+
+  public DomainToElementStrategy() {
+    super("Domain");
+  }
 
   @Override
   public Element toElement(final EntityInterface entity, final SetFieldStrategy setFieldStrategy) {
-    return EntityToElementStrategy.sparseEntityToElement("Domain", entity, setFieldStrategy);
+    Element element = new Element(tagName);
+    sparseEntityToElement(element, entity, setFieldStrategy);
+    return element;
   }
 
   @Override
diff --git a/src/main/java/caosdb/server/entity/xml/EntityToElementStrategy.java b/src/main/java/caosdb/server/entity/xml/EntityToElementStrategy.java
index 19bfe80c6b5a35b8cc214ffb6c260294633b8495..ae69b94024eac0fdd9667233b507545e2b0f09af 100644
--- a/src/main/java/caosdb/server/entity/xml/EntityToElementStrategy.java
+++ b/src/main/java/caosdb/server/entity/xml/EntityToElementStrategy.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -22,27 +24,62 @@
  */
 package caosdb.server.entity.xml;
 
+import caosdb.server.datatype.ReferenceValue;
 import caosdb.server.entity.EntityInterface;
 import caosdb.server.entity.Message;
 import caosdb.server.utils.EntityStatus;
 import caosdb.server.utils.TransactionLogMessage;
-import java.util.Comparator;
 import org.apache.shiro.SecurityUtils;
-import org.jdom2.Content;
-import org.jdom2.Content.CType;
+import org.jdom2.Attribute;
 import org.jdom2.Element;
 
+/**
+ * Base class for the generation of a JDOM (XML) representation for entities.
+ *
+ * <p>Record and RecordType entities use this class only. Properties, Parents, Files and other
+ * entities have specialized sub classes.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class EntityToElementStrategy implements ToElementStrategy {
 
-  private final String tagName;
+  protected final String tagName;
 
   public EntityToElementStrategy(final String tagName) {
     this.tagName = tagName;
   }
 
-  public static Element sparseEntityToElement(
-      final String tagName, final EntityInterface entity, final SetFieldStrategy setFieldStrategy) {
-    final Element element = new Element(tagName);
+  /**
+   * Set the data type of this entity as a JDOM {@link Attribute} of the given element.
+   *
+   * <p>If the data type has a name, the name is used, otherwise the id is used.
+   *
+   * @param entity
+   * @param element
+   */
+  public void setDatatype(EntityInterface entity, Element element) {
+    if (entity.getDatatype().getName() != null) {
+      element.setAttribute("datatype", entity.getDatatype().getName());
+    } else {
+      element.setAttribute("datatype", entity.getDatatype().getId().toString());
+    }
+  }
+
+  /**
+   * Set all properties of the entity that are considered to be part of the sparse entity, e.g.
+   * name, description, etc, as {@link Attribute} of the given element.
+   *
+   * <p>The setFieldStrategy decides which attributes are set if present and which are omitted in
+   * any case.
+   *
+   * @param element
+   * @param entity
+   * @param setFieldStrategy
+   */
+  public void sparseEntityToElement(
+      final Element element,
+      final EntityInterface entity,
+      final SetFieldStrategy setFieldStrategy) {
 
     if (entity.getEntityACL() != null) {
       element.addContent(entity.getEntityACL().getPermissionsFor(SecurityUtils.getSubject()));
@@ -60,11 +97,7 @@ public class EntityToElementStrategy implements ToElementStrategy {
       element.setAttribute("description", entity.getDescription());
     }
     if (setFieldStrategy.isToBeSet("datatype") && entity.hasDatatype()) {
-      if (entity.getDatatype().getName() != null) {
-        element.setAttribute("datatype", entity.getDatatype().getName());
-      } else {
-        element.setAttribute("datatype", entity.getDatatype().getId().toString());
-      }
+      setDatatype(entity, element);
     }
     if (setFieldStrategy.isToBeSet("message") && entity.hasMessages()) {
       for (final ToElementable m : entity.getMessages()) {
@@ -76,55 +109,78 @@ public class EntityToElementStrategy implements ToElementStrategy {
       q.setText(entity.getQueryTemplateDefinition());
       element.addContent(q);
     }
+  }
 
-    return element;
+  /**
+   * Set the value of the entity.
+   *
+   * <p>The setFieldStrategy decides if the value is to be set at all.
+   *
+   * <p>If the value is a reference, the setFieldStrategy decides whether the referenced entity is
+   * added as a deep Element tree (as a whole, so to speak) or just the ID of the referenced entity.
+   *
+   * @param entity
+   * @param element
+   * @param setFieldStrategy
+   */
+  public void setValue(EntityInterface entity, Element element, SetFieldStrategy setFieldStrategy) {
+    if (entity.hasValue()) {
+      try {
+        entity.parseValue();
+      } catch (final Message | NullPointerException e) {
+        // Ignore. Parsing the value failed. But that does not concern us here, because this is the
+        // case when a write transaction failed. The error for that has already been handled by the
+        // CheckValueParsable job.
+      }
+
+      if (entity.getValue() instanceof ReferenceValue
+          && setFieldStrategy.isToBeSet("_referenced")) {
+        // Append the complete entity. This needs to be done when we are
+        // processing SELECT Queries.
+        EntityInterface ref = ((ReferenceValue) entity.getValue()).getEntity();
+        if (ref != null) {
+          if (entity.hasDatatype()) {
+            setDatatype(entity, element);
+          }
+          ref.addToElement(element, setFieldStrategy);
+          // the referenced entity has been appended. Return here to suppress
+          // adding the reference id as well.
+          return;
+        }
+      }
+
+      if (setFieldStrategy.isToBeSet("value")) {
+        if (entity.hasDatatype()) {
+          setDatatype(entity, element);
+        }
+        entity.getValue().addToElement(element);
+      }
+    }
   }
 
   @Override
   public Element toElement(final EntityInterface entity, final SetFieldStrategy setFieldStrategy) {
-    final Element element = sparseEntityToElement(this.tagName, entity, setFieldStrategy);
+    final Element element = new Element(tagName);
+
+    // always have the values at the beginning of the children
+    setValue(entity, element, setFieldStrategy);
 
-    if (setFieldStrategy.isToBeSet("importance") && entity.hasStatementStatus()) {
+    sparseEntityToElement(element, entity, setFieldStrategy);
+
+    if (entity.hasStatementStatus() && setFieldStrategy.isToBeSet("importance")) {
       element.setAttribute("importance", entity.getStatementStatus().toString());
     }
-    if (setFieldStrategy.isToBeSet("parent") && entity.hasParents()) {
+    if (entity.hasParents() && setFieldStrategy.isToBeSet("parent")) {
       entity.getParents().addToElement(element);
     }
     if (entity.hasProperties()) {
       entity.getProperties().addToElement(element, setFieldStrategy);
     }
-    if (setFieldStrategy.isToBeSet("history") && entity.hasTransactionLogMessages()) {
+    if (entity.hasTransactionLogMessages() && setFieldStrategy.isToBeSet("history")) {
       for (final TransactionLogMessage t : entity.getTransactionLogMessages()) {
         t.xmlAppendTo(element);
       }
     }
-    if (setFieldStrategy.isToBeSet("value") && entity.hasValue()) {
-      if (entity.hasDatatype()) {
-        try {
-
-          entity.getDatatype().parseValue(entity.getValue()).addToElement(element);
-        } catch (final Message e) {
-          //
-        }
-      } else {
-        entity.getValue().addToElement(element);
-      }
-      // put value at first position
-      element.sortContent(
-          new Comparator<Content>() {
-
-            @Override
-            public int compare(final Content o1, final Content o2) {
-              if (o1.getCType() == CType.CDATA || o1.getCType() == CType.Text) {
-                return -1;
-              }
-              if (o2.getCType() == CType.CDATA || o2.getCType() == CType.Text) {
-                return 1;
-              }
-              return 0;
-            }
-          });
-    }
     return element;
   }
 
diff --git a/src/main/java/caosdb/server/entity/xml/ParentToElementStrategy.java b/src/main/java/caosdb/server/entity/xml/ParentToElementStrategy.java
index 0d79951f5554b4c2c346224f3b6e91c1c056a96e..2498e00bfda219eb5e724a7c38bc73cc4ad3468e 100644
--- a/src/main/java/caosdb/server/entity/xml/ParentToElementStrategy.java
+++ b/src/main/java/caosdb/server/entity/xml/ParentToElementStrategy.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -27,17 +29,26 @@ import caosdb.server.entity.wrapper.Parent;
 import caosdb.server.utils.EntityStatus;
 import org.jdom2.Element;
 
-public class ParentToElementStrategy implements ToElementStrategy {
+/**
+ * Generates a JDOM (XML) representation of an entity's parent.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
+public class ParentToElementStrategy extends EntityToElementStrategy {
+
+  public ParentToElementStrategy() {
+    super("Parent");
+  }
 
   @Override
   public Element toElement(final EntityInterface entity, final SetFieldStrategy setFieldStrategy) {
-    final Element e =
-        EntityToElementStrategy.sparseEntityToElement("Parent", entity, setFieldStrategy);
+    final Element element = new Element(this.tagName);
+    sparseEntityToElement(element, entity, setFieldStrategy);
     final Parent parent = (Parent) entity;
     if (parent.getAffiliation() != null) {
-      e.setAttribute("affiliation", parent.getAffiliation().toString());
+      element.setAttribute("affiliation", parent.getAffiliation().toString());
     }
-    return e;
+    return element;
   }
 
   @Override
diff --git a/src/main/java/caosdb/server/entity/xml/SetFieldStrategy.java b/src/main/java/caosdb/server/entity/xml/SetFieldStrategy.java
index 7299659900014c4800b3fe0b8864cd7d15409380..3e7e735e6d863721a7591b8a2fc18f6fc9dfa15c 100644
--- a/src/main/java/caosdb/server/entity/xml/SetFieldStrategy.java
+++ b/src/main/java/caosdb/server/entity/xml/SetFieldStrategy.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -23,20 +25,34 @@
 package caosdb.server.entity.xml;
 
 import caosdb.server.entity.EntityInterface;
+import caosdb.server.query.Query;
 import caosdb.server.query.Query.Selection;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 
+/**
+ * A class which decides whether the properties, parents, name, etc. of an entity are to be included
+ * into the serialization or not.
+ *
+ * <p>The decision is based on a list of {@link Query.Selection} or smart defaults.
+ *
+ * @author Timm Fitschen <t.fitschen@indiscale.com>
+ */
 public class SetFieldStrategy {
 
   private final List<Selection> selections = new LinkedList<Selection>();
   private HashMap<String, Boolean> cache = null;
+
+  /**
+   * The default is: Any field should be included into the serialization, unless it is a referenced
+   * entity.
+   */
   private static final SetFieldStrategy defaultSelections =
       new SetFieldStrategy(null) {
         @Override
         public boolean isToBeSet(final String field) {
-          return true;
+          return field == null || !field.equalsIgnoreCase("_referenced");
         }
       };
 
@@ -68,8 +84,9 @@ public class SetFieldStrategy {
     return forProperty(property.getName());
   }
 
+  /** Return the strategy for a property. */
   public SetFieldStrategy forProperty(final String name) {
-    // if property is to be omitted.
+    // if property is to be omitted: always-false-strategy
     if (!isToBeSet(name)) {
       return new SetFieldStrategy() {
         @Override
@@ -85,6 +102,23 @@ public class SetFieldStrategy {
         subselections.add(s.getSubselection());
       }
     }
+    if (subselections.isEmpty() && this.isToBeSet("_referenced")) {
+
+      /**
+       * If the super selection decided that the referenced entity is to be included into the
+       * serialization, while it doesn't specify the subselects, every field is to be included.
+       *
+       * <p>This is the case when the selections are deeply nested but only the very last segments
+       * are actually used, e.g ["a.b.c.d1", "a.b.c.d2"].
+       */
+      return new SetFieldStrategy() {
+        // Always-true-strategy
+        @Override
+        public boolean isToBeSet(String field) {
+          return true;
+        }
+      };
+    }
     return new SetFieldStrategy(subselections);
   }
 
@@ -94,13 +128,23 @@ public class SetFieldStrategy {
       return defaultSelections.isToBeSet(field);
     }
 
+    // There must be a least one selection defined, a null field won't match anything.
+    if (field == null) {
+      return false;
+    }
+
     if (this.cache == null) {
       this.cache = new HashMap<String, Boolean>();
-      // fill cache
+      // always include the id and the name
       this.cache.put("id", true);
+      this.cache.put("name", true);
+
+      // ... and the referenced entity.
+      this.cache.put("_referenced", true);
       for (final Selection selection : this.selections) {
-        if (!selection.getSelector().equals("id")) {
-          this.cache.put("name", true);
+        if (selection.getSelector().equals("value")) {
+          // if the value is present, the data type is needed as well
+          this.cache.put("datatype", true);
         }
         this.cache.put(selection.getSelector().toLowerCase(), true);
       }
diff --git a/src/main/java/caosdb/server/jobs/extension/JobException.java b/src/main/java/caosdb/server/jobs/extension/JobException.java
deleted file mode 100644
index e41475bb370334bb85f0ee8adfb14219d7ecf44d..0000000000000000000000000000000000000000
--- a/src/main/java/caosdb/server/jobs/extension/JobException.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-package caosdb.server.jobs.extension;
-
-import caosdb.server.jobs.Job;
-
-public class JobException extends RuntimeException {
-
-  /** */
-  private static final long serialVersionUID = -2802983933079999366L;
-
-  private final Job job;
-
-  public JobException(final Job job, final Exception e) {
-    super(e);
-    this.job = job;
-  }
-
-  public Job getJob() {
-    return this.job;
-  }
-}
diff --git a/src/main/java/caosdb/server/jobs/extension/SQLiteTransaction.java b/src/main/java/caosdb/server/jobs/extension/SQLiteTransaction.java
deleted file mode 100644
index 4882f0aff290cc53f80372f1451b538c664dae56..0000000000000000000000000000000000000000
--- a/src/main/java/caosdb/server/jobs/extension/SQLiteTransaction.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-package caosdb.server.jobs.extension;
-
-import caosdb.server.CaosDBException;
-import caosdb.server.entity.FileProperties;
-import caosdb.server.entity.Message;
-import caosdb.server.jobs.EntityJob;
-import caosdb.server.utils.FileUtils;
-import java.io.IOException;
-import java.security.NoSuchAlgorithmException;
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.concurrent.locks.ReentrantLock;
-
-public class SQLiteTransaction extends EntityJob {
-  private static HashMap<String, ReentrantLock> lockedTables = new HashMap<String, ReentrantLock>();
-
-  @SuppressWarnings("unlikely-arg-type")
-  @Override
-  public final void run() {
-    Connection con = null;
-    try {
-      if (getEntity().hasFileProperties()) {
-        if (getEntity().getFileProperties().retrieveFromFileSystem() != null) {
-
-          if (getEntity().hasMessage("execute")) {
-            try {
-              if (!lockedTables.containsKey(
-                  getEntity().getFileProperties().getFile().getCanonicalPath())) {
-                synchronized (lockedTables) {
-                  lockedTables.put(
-                      getEntity().getFileProperties().getFile().getCanonicalPath(),
-                      new ReentrantLock());
-                }
-              }
-
-              lockedTables.get(getEntity().getFileProperties().getFile().getCanonicalPath()).lock();
-              try {
-                con =
-                    getConnection(
-                        getEntity()
-                            .getFileProperties()
-                            .retrieveFromFileSystem()
-                            .getCanonicalPath());
-                final Statement stmt = con.createStatement();
-
-                //
-                final List<Message> msgs = getEntity().getMessages("execute");
-                Collections.sort(msgs);
-                for (final Message m : msgs) {
-                  getEntity().removeMessage(m);
-                  stmt.execute(m.getBody());
-                  final ResultSet rs = stmt.getResultSet();
-                  final int updateCount = stmt.getUpdateCount();
-                  if (rs != null) {
-                    final ResultSetMetaData rsmd = rs.getMetaData();
-                    final int columns = rsmd.getColumnCount();
-                    final StringBuilder s = new StringBuilder();
-                    if (columns > 0) {
-                      s.append("|");
-                      for (int i = 1; i <= columns; i++) {
-                        s.append(rsmd.getColumnName(i));
-                        s.append("|");
-                      }
-                      s.append("\n");
-                      while (rs.next()) {
-                        s.append("|");
-                        for (int i = 1; i <= columns; i++) {
-                          s.append(rs.getString(i));
-                          s.append("|");
-                        }
-                        s.append("\n");
-                      }
-                    } else {
-                      s.append("");
-                    }
-                    final Message mret = new Message("result", m.getCode(), null, s.toString());
-                    getEntity().addMessage(mret);
-
-                  } else if (updateCount != -1) {
-                    final Message mret =
-                        new Message(
-                            "result",
-                            m.getCode(),
-                            null,
-                            Integer.toString(updateCount) + " row(s) affected by the query.");
-                    getEntity().addMessage(mret);
-                  }
-                }
-              } finally {
-                lockedTables
-                    .get(getEntity().getFileProperties().getFile().getCanonicalPath())
-                    .unlock();
-              }
-              synchronized (
-                  lockedTables.get(getEntity().getFileProperties().getFile().getCanonicalPath())) {
-                if (!lockedTables
-                    .get(getEntity().getFileProperties().getFile().getCanonicalPath())
-                    .hasQueuedThreads()) {
-                  lockedTables.remove(
-                      lockedTables.get(
-                          getEntity().getFileProperties().getFile().getCanonicalPath()));
-                }
-              }
-            } finally {
-              if (con != null && !con.isClosed()) {
-                con.close();
-              }
-              resetSizeAndChecksum(getEntity().getFileProperties());
-            }
-          }
-        }
-      }
-    } catch (final NoSuchAlgorithmException e) {
-      throw new JobException(this, e);
-    } catch (final IOException e) {
-      throw new JobException(this, e);
-    } catch (final CaosDBException e) {
-      throw new JobException(this, e);
-    } catch (final ClassNotFoundException e) {
-      throw new JobException(this, e);
-    } catch (final SQLException e) {
-      throw new JobException(this, e);
-    }
-  }
-
-  private static void resetSizeAndChecksum(final FileProperties f)
-      throws NoSuchAlgorithmException, IOException {
-    f.setSize(f.getFile().length());
-    f.setChecksum(FileUtils.getChecksum(f.getFile()));
-  }
-
-  private static Connection getConnection(final String database)
-      throws ClassNotFoundException, SQLException {
-    if (!driverLoaded) {
-      Class.forName("org.sqlite.JDBC");
-      driverLoaded = true;
-    }
-    final Connection connection = DriverManager.getConnection("jdbc:sqlite:" + database);
-    return connection;
-  }
-
-  private static boolean driverLoaded = false;
-}
diff --git a/src/main/java/caosdb/server/query/Query.java b/src/main/java/caosdb/server/query/Query.java
index 1f85826967cf5020cdbdb6ecbbfe4e9452b9d929..4eeaafc03a8f94b0df845aff40a923d1f52dc60a 100644
--- a/src/main/java/caosdb/server/query/Query.java
+++ b/src/main/java/caosdb/server/query/Query.java
@@ -66,18 +66,20 @@ import org.jdom2.Element;
 
 public class Query implements QueryInterface, ToElementable, TransactionInterface {
 
+  /** Class which represents the selection of (sub)properties. */
   public static class Selection {
     private final String selector;
     private Selection subselection = null;
 
     public Selection setSubSelection(final Selection sub) {
       if (this.subselection != null) {
-        throw new UnsupportedOperationException("subselection is immutble!");
+        throw new UnsupportedOperationException("SubSelection is immutable!");
       }
       this.subselection = sub;
       return this;
     }
 
+    /** No parsing, just sets the selector string. */
     public Selection(final String selector) {
       this.selector = selector.trim();
     }
diff --git a/src/test/java/caosdb/server/database/backend/transaction/RetrieveFullEntityTest.java b/src/test/java/caosdb/server/database/backend/transaction/RetrieveFullEntityTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..78c2ae8206fbe5aac33ee4d9d9d73b2fae5965ef
--- /dev/null
+++ b/src/test/java/caosdb/server/database/backend/transaction/RetrieveFullEntityTest.java
@@ -0,0 +1,79 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+package caosdb.server.database.backend.transaction;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import caosdb.server.datatype.ReferenceValue;
+import caosdb.server.entity.Entity;
+import caosdb.server.entity.EntityInterface;
+import caosdb.server.entity.wrapper.Property;
+import caosdb.server.entity.xml.PropertyToElementStrategyTest;
+import caosdb.server.query.Query.Selection;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+
+public class RetrieveFullEntityTest {
+
+  @Test
+  public void testRetrieveSubEntities() {
+    RetrieveFullEntity r =
+        new RetrieveFullEntity(0) {
+
+          /** Mock-up */
+          @Override
+          public void retrieveFullEntity(EntityInterface e, List<Selection> selections) {
+            // The id of the referenced window
+            assertEquals(1234, (int) e.getId());
+
+            // The level of selectors has been reduced by 1
+            assertEquals("description", selections.get(0).getSelector());
+
+            e.setDescription("A heart-shaped window.");
+          };
+        };
+
+    Property window = new Property(2345);
+    window.setName("Window");
+    window.setDatatype("Window");
+    window.setValue(new ReferenceValue(1234));
+
+    Entity house = new Entity();
+    house.addProperty(window);
+    ReferenceValue value = (ReferenceValue) house.getProperties().getEntityById(2345).getValue();
+    assertEquals(1234, (int) value.getId());
+    assertNull(value.getEntity());
+
+    List<Selection> selections = new ArrayList<>();
+    selections.add(PropertyToElementStrategyTest.parse("window.description"));
+
+    r.retrieveSubEntities(house, selections);
+
+    assertEquals(1234, (int) value.getId());
+    assertNotNull(value.getEntity());
+    assertEquals("A heart-shaped window.", value.getEntity().getDescription());
+  }
+}
diff --git a/src/test/java/caosdb/server/entity/SelectionTest.java b/src/test/java/caosdb/server/entity/SelectionTest.java
index cc961b9a5cfa47c022cfdf63201ea53613758a32..068a87c48a0257925d120613f83b4741173873d1 100644
--- a/src/test/java/caosdb/server/entity/SelectionTest.java
+++ b/src/test/java/caosdb/server/entity/SelectionTest.java
@@ -4,6 +4,8 @@
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -22,13 +24,26 @@
  */
 package caosdb.server.entity;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import caosdb.server.CaosDBServer;
 import caosdb.server.entity.xml.SetFieldStrategy;
+import caosdb.server.query.Query;
 import caosdb.server.query.Query.Selection;
+import java.io.IOException;
 import org.junit.Assert;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 public class SelectionTest {
 
+  @BeforeClass
+  public static void initServerProperties() throws IOException {
+    CaosDBServer.initServerProperties();
+  }
+
   @Test
   public void testEmpty1() {
     final SetFieldStrategy setFieldStrategy = new SetFieldStrategy();
@@ -59,7 +74,7 @@ public class SelectionTest {
     final Selection selection = new Selection("id");
     final SetFieldStrategy setFieldStrategy = (new SetFieldStrategy()).addSelection(selection);
 
-    Assert.assertFalse(setFieldStrategy.isToBeSet("name"));
+    Assert.assertTrue(setFieldStrategy.isToBeSet("name"));
   }
 
   @Test
@@ -262,16 +277,50 @@ public class SelectionTest {
             .addSelection(new Selection("blabla").setSubSelection(new Selection("value")))
             .addSelection(new Selection("blabla").setSubSelection(new Selection("description")));
 
-    Assert.assertTrue(setFieldStrategy.isToBeSet("blabla"));
-    Assert.assertTrue(setFieldStrategy.isToBeSet("id"));
-    Assert.assertTrue(setFieldStrategy.isToBeSet("name"));
-    Assert.assertFalse(setFieldStrategy.isToBeSet("bleb"));
+    assertTrue(setFieldStrategy.isToBeSet("blabla"));
+    assertTrue(setFieldStrategy.isToBeSet("id"));
+    assertTrue(setFieldStrategy.isToBeSet("name"));
+    assertFalse(setFieldStrategy.isToBeSet("bleb"));
 
     final SetFieldStrategy forProperty = setFieldStrategy.forProperty("blabla");
-    Assert.assertTrue(forProperty.isToBeSet("id"));
-    Assert.assertTrue(forProperty.isToBeSet("name"));
-    Assert.assertTrue(forProperty.isToBeSet("description"));
-    Assert.assertTrue(forProperty.isToBeSet("value"));
-    Assert.assertFalse(forProperty.isToBeSet("blub"));
+    assertTrue(forProperty.isToBeSet("id"));
+    assertTrue(forProperty.isToBeSet("name"));
+    assertTrue(forProperty.isToBeSet("description"));
+    assertTrue(forProperty.isToBeSet("value"));
+    assertFalse(forProperty.isToBeSet("blub"));
+  }
+
+  @Test
+  public void testSubSubSelection() {
+    String query_str = "SELECT property.subproperty.subsubproperty FROM ENTITY";
+    Query query = new Query(query_str);
+    query.parse();
+    assertEquals(query.getSelections().size(), 1);
+
+    Selection s = query.getSelections().get(0);
+    assertEquals(s.toString(), "property.subproperty.subsubproperty");
+    assertEquals(s.getSubselection().toString(), "subproperty.subsubproperty");
+    assertEquals(s.getSubselection().getSubselection().toString(), "subsubproperty");
+  }
+
+  @Test
+  public void testSubSubProperty() {
+    Selection s =
+        new Selection("property")
+            .setSubSelection(
+                new Selection("subproperty").setSubSelection(new Selection("subsubproperty")));
+
+    assertEquals(s.toString(), "property.subproperty.subsubproperty");
+
+    SetFieldStrategy setFieldStrategy = new SetFieldStrategy().addSelection(s);
+    assertTrue(setFieldStrategy.isToBeSet("property"));
+    assertFalse(setFieldStrategy.forProperty("property").isToBeSet("sadf"));
+    //    assertFalse(setFieldStrategy.forProperty("property").isToBeSet("name"));
+    assertTrue(setFieldStrategy.forProperty("property").isToBeSet("subproperty"));
+    assertTrue(
+        setFieldStrategy
+            .forProperty("property")
+            .forProperty("subproperty")
+            .isToBeSet("subsubproperty"));
   }
 }
diff --git a/src/test/java/caosdb/server/entity/container/PropertyContainerTest.java b/src/test/java/caosdb/server/entity/container/PropertyContainerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0678e83072a4f6f3f93aacb8a9f4196d5a566c2e
--- /dev/null
+++ b/src/test/java/caosdb/server/entity/container/PropertyContainerTest.java
@@ -0,0 +1,80 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+package caosdb.server.entity.container;
+
+import static org.junit.Assert.assertEquals;
+
+import caosdb.server.datatype.GenericValue;
+import caosdb.server.datatype.ReferenceValue;
+import caosdb.server.entity.Entity;
+import caosdb.server.entity.Role;
+import caosdb.server.entity.wrapper.Property;
+import caosdb.server.entity.xml.PropertyToElementStrategyTest;
+import caosdb.server.entity.xml.SetFieldStrategy;
+import org.jdom2.Element;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class PropertyContainerTest {
+
+  public static Entity house = null;
+  public static Property houseHeight = null;
+  public static Entity window = null;
+  public static Property windowHeight = null;
+  public static Entity houseOwner = null;
+  public static Property windowProperty = null;
+
+  @BeforeClass
+  public static void setup() {
+    window = new Entity(1234);
+    windowHeight = new Property(new Entity("window.height", Role.Property));
+    window.addProperty(windowHeight);
+    windowHeight.setValue(new GenericValue("windowHeight"));
+
+    houseOwner = new Entity("The Queen", Role.Record);
+
+    house = new Entity("Buckingham Palace", Role.Record);
+    houseHeight = new Property(new Entity("height", Role.Property));
+    houseHeight.setValue(new GenericValue("houseHeight"));
+    house.addProperty(houseHeight);
+    windowProperty = new Property(2345);
+    windowProperty.setName("window");
+    windowProperty.setValue(new ReferenceValue(window.getId()));
+    house.addProperty(windowProperty);
+
+    house.addProperty(new Property());
+    house.addProperty(new Property(houseHeight));
+  }
+
+  @Test
+  public void test() {
+    PropertyContainer container = new PropertyContainer(new Entity());
+    Element element = new Element("Record");
+    SetFieldStrategy setFieldStrategy =
+        new SetFieldStrategy().addSelection(PropertyToElementStrategyTest.parse("window.height"));
+
+    container.addToElement(windowProperty, element, setFieldStrategy);
+
+    assertEquals(1, element.getChildren().size());
+  }
+}
diff --git a/src/test/java/caosdb/server/entity/xml/PropertyToElementStrategyTest.java b/src/test/java/caosdb/server/entity/xml/PropertyToElementStrategyTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e0feec8915283170b2964420d3ef1f6a42c0031
--- /dev/null
+++ b/src/test/java/caosdb/server/entity/xml/PropertyToElementStrategyTest.java
@@ -0,0 +1,105 @@
+/*
+ * ** header v3.0
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * ** end header
+ */
+package caosdb.server.entity.xml;
+
+import static org.junit.Assert.assertEquals;
+
+import caosdb.server.datatype.GenericValue;
+import caosdb.server.datatype.ReferenceValue;
+import caosdb.server.entity.Entity;
+import caosdb.server.entity.EntityInterface;
+import caosdb.server.entity.Role;
+import caosdb.server.entity.wrapper.Property;
+import caosdb.server.query.Query.Selection;
+import org.jdom2.Element;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PropertyToElementStrategyTest {
+
+  public static Entity house = null;
+  public static Property houseHeight = null;
+  public static Entity window = null;
+  public static Property windowHeight = null;
+  public static Entity houseOwner = null;
+  public static Property windowProperty = null;
+
+  /**
+   * Create a nested selection out of the dot-separated parts of <code>select</code>.
+   *
+   * <p>The returned Selection has nested subselections, so that each subselection corresponds to
+   * the next part and the remainder of the initial <code>select</code> String.
+   */
+  public static Selection parse(String select) {
+    String[] split = select.split("\\.");
+    Selection result = new Selection(split[0]);
+    Selection next = result;
+
+    for (int i = 1; i < split.length; i++) {
+      next.setSubSelection(new Selection(split[i]));
+      next = next.getSubselection();
+    }
+    return result;
+  }
+
+  @Before
+  public void setup() {
+    window = new Entity(1234, Role.Record);
+    windowHeight = new Property(new Entity("height", Role.Property));
+    window.addProperty(windowHeight);
+    windowHeight.setValue(new GenericValue("windowHeight"));
+
+    houseOwner = new Entity("The Queen", Role.Record);
+
+    house = new Entity("Buckingham Palace", Role.Record);
+    houseHeight = new Property(new Entity("height", Role.Property));
+    houseHeight.setValue(new GenericValue("houseHeight"));
+    house.addProperty(houseHeight);
+    windowProperty = new Property(2345);
+    windowProperty.setName("window");
+    windowProperty.setValue(new ReferenceValue(window.getId()));
+    house.addProperty(windowProperty);
+
+    house.addProperty(new Property());
+    house.addProperty(new Property(houseHeight));
+  }
+
+  @Test
+  public void test() {
+    PropertyToElementStrategy strategy = new PropertyToElementStrategy();
+    SetFieldStrategy setFieldStrategy = new SetFieldStrategy().addSelection(parse("height"));
+    EntityInterface property = windowProperty;
+    ((ReferenceValue) property.getValue()).setEntity(window);
+    Element element = strategy.toElement(property, setFieldStrategy);
+    assertEquals("Property", element.getName());
+    assertEquals("2345", element.getAttributeValue("id"));
+    assertEquals("window", element.getAttributeValue("name"));
+    assertEquals(1, element.getChildren().size());
+    assertEquals("Record", element.getChildren().get(0).getName());
+
+    Element recordElement = element.getChild("Record");
+    assertEquals("1234", recordElement.getAttributeValue("id"));
+    assertEquals(1, recordElement.getChildren().size());
+    assertEquals("windowHeight", recordElement.getChild("Property").getText());
+  }
+}