diff --git a/src/main/java/org/caosdb/server/entity/Entity.java b/src/main/java/org/caosdb/server/entity/Entity.java
index 48a92fd053cce0cadb86785c4a13d73db7359e08..317aea4dfc9e15e2115817621a455f083ff3d5b5 100644
--- a/src/main/java/org/caosdb/server/entity/Entity.java
+++ b/src/main/java/org/caosdb/server/entity/Entity.java
@@ -809,14 +809,13 @@ public abstract class Entity extends AbstractObservable implements EntityInterfa
     if (tmpIdentifier != null || checksum != null || path != null || size != null) {
       // legacy clients (which use this api) always use sha512.
       Hash hash = Hash.create(checksum, 0, Hasher.Default);
-      setFSODescriptor(
-          new FSODescriptor(
-              FileSystem.DEFAULT_BACKEND,
-              new Path(path).toString(),
-              hash,
-              new Path(path),
-              size,
-              tmpIdentifier));
+      if (getRole() == Role.Directory) {
+        setFSODescriptor(FSODescriptor.createDir(FileSystem.DEFAULT_BACKEND, new Path(path)));
+      } else {
+        setFSODescriptor(
+            new FSODescriptor(
+                FileSystem.DEFAULT_BACKEND, null, hash, new Path(path), size, tmpIdentifier));
+      }
     }
 
     // Parse flags
diff --git a/src/main/java/org/caosdb/server/entity/MagicTypes.java b/src/main/java/org/caosdb/server/entity/MagicTypes.java
index 39556385235e6b72736bed8dff67a178cfe60aff..289fae6e9164c66a8921b765a7275a0ac6a493e3 100644
--- a/src/main/java/org/caosdb/server/entity/MagicTypes.java
+++ b/src/main/java/org/caosdb/server/entity/MagicTypes.java
@@ -31,11 +31,13 @@ import org.caosdb.server.transaction.Retrieve;
 public enum MagicTypes {
   UNIT,
   NAME,
-  DESCRIPTION;
+  DESCRIPTION,
+  ROOT_DIRECTORY;
 
   private static final EntityID UNIT_ID = new EntityID(21);
   private static final EntityID DESCRIPTION_ID = new EntityID(24);
   private static final EntityID NAME_ID = new EntityID(20);
+  private static final EntityID ROOT_DIRECTORY_ID = new EntityID(51);
 
   public EntityID getId() {
     switch (this) {
@@ -45,6 +47,8 @@ public enum MagicTypes {
         return NAME_ID;
       case DESCRIPTION:
         return DESCRIPTION_ID;
+      case ROOT_DIRECTORY:
+        return ROOT_DIRECTORY_ID;
       default:
         return null;
     }
@@ -58,6 +62,8 @@ public enum MagicTypes {
         return NAME;
       case 24:
         return DESCRIPTION;
+      case 51:
+        return ROOT_DIRECTORY;
       default:
         return null;
     }
diff --git a/src/main/java/org/caosdb/server/entity/Role.java b/src/main/java/org/caosdb/server/entity/Role.java
index 1ce6329d67ac97cb9e520604ceb30d2d1cd938d1..53bc3a47a9c78c8dfd753e3f2e8128788bade3bf 100644
--- a/src/main/java/org/caosdb/server/entity/Role.java
+++ b/src/main/java/org/caosdb/server/entity/Role.java
@@ -35,7 +35,6 @@ public enum Role {
   Domain,
   File,
   Directory,
-  Link,
   Property,
   DataType,
   QueryTemplate;
@@ -75,14 +74,12 @@ public enum Role {
         return new FileToElementStrategy(toString());
       case Directory:
         return new FileToElementStrategy(toString());
-      case Link:
-        return new FileToElementStrategy(toString());
       default:
         return new EntityToElementStrategy(toString());
     }
   }
 
   public boolean hasFSODescriptor() {
-    return this == File; // || this == Directory;
+    return this == File || this == Directory;
   }
 }
diff --git a/src/main/java/org/caosdb/server/filesystem/FSODescriptor.java b/src/main/java/org/caosdb/server/filesystem/FSODescriptor.java
index d1b59ca881eda0d831a037b0cd189894b4f2ea46..5290f8698e828cd5da4a6b953690a9710834847f 100644
--- a/src/main/java/org/caosdb/server/filesystem/FSODescriptor.java
+++ b/src/main/java/org/caosdb/server/filesystem/FSODescriptor.java
@@ -187,8 +187,9 @@ public class FSODescriptor implements VirtualFSODescriptorInterface {
     this.children = children;
   }
 
-  public static FSODescriptor createDir(final Path dirPath) {
+  public static FSODescriptor createDir(String fileStorageId, final Path dirPath) {
     final FSODescriptor ret = new FSODescriptor(dirPath);
+    ret.fileStorageId = fileStorageId;
     ret.type = ObjectType.DIRECTORY;
     return ret;
   }
@@ -252,4 +253,9 @@ public class FSODescriptor implements VirtualFSODescriptorInterface {
   public void setTwin(RealFSODescriptorInterface twin) {
     this.twin = twin;
   }
+
+  @Override
+  public void setKey(String key) {
+    this.key = key;
+  }
 }
diff --git a/src/main/java/org/caosdb/server/filesystem/FileStorageInterface.java b/src/main/java/org/caosdb/server/filesystem/FileStorageInterface.java
index 19420a8527576c35ba29dc8eba39f1484840b9c9..e2bca5afea193b9727534bdc153c4f4aa825468b 100644
--- a/src/main/java/org/caosdb/server/filesystem/FileStorageInterface.java
+++ b/src/main/java/org/caosdb/server/filesystem/FileStorageInterface.java
@@ -39,7 +39,8 @@ public interface FileStorageInterface {
    */
   public abstract RealFSODescriptorInterface resolve(String fileKey);
 
-  public abstract Undoable move(RealFSODescriptorInterface file, String fileKey) throws Message;
+  public abstract Undoable move(
+      RealFSODescriptorInterface file, VirtualFSODescriptorInterface target) throws Message;
 
   public abstract Undoable delete(String fileKey) throws Message;
 
diff --git a/src/main/java/org/caosdb/server/filesystem/FileSystem.java b/src/main/java/org/caosdb/server/filesystem/FileSystem.java
index e016d7952f96e0a43e5a8f878e41e5f1f44f9223..800a003bf58de1c92d86e636e54a6434136b8d0f 100644
--- a/src/main/java/org/caosdb/server/filesystem/FileSystem.java
+++ b/src/main/java/org/caosdb/server/filesystem/FileSystem.java
@@ -46,12 +46,6 @@ public class FileSystem implements FileSystemInterface {
     return fs.delete(file.getKey());
   }
 
-  @Override
-  public Undoable store(final RealFSODescriptorInterface file) throws Message {
-    final FileStorageInterface fs = getFileStorage(file);
-    return fs.move(file, file.getKey());
-  }
-
   public static FileSystem getInstance() {
     return instance;
   }
@@ -98,10 +92,10 @@ public class FileSystem implements FileSystemInterface {
     return null;
   }
 
-  public Undoable move(RealFSODescriptorInterface fso, FSODescriptorInterface target)
+  public Undoable move(RealFSODescriptorInterface fso, VirtualFSODescriptorInterface target)
       throws Message {
     FileStorageInterface fileStorage = getFileStorage(target);
-    return fileStorage.move(fso, target.getKey());
+    return fileStorage.move(fso, target);
   }
 
   //  public static boolean resolve(FSODescriptorInterface fso) {
diff --git a/src/main/java/org/caosdb/server/filesystem/FileSystemInterface.java b/src/main/java/org/caosdb/server/filesystem/FileSystemInterface.java
index 33cd2204f8971a6b68c59b3471b80119e8e64b5f..a28cff1df4a8b927f108dc2d06a316812a521fcc 100644
--- a/src/main/java/org/caosdb/server/filesystem/FileSystemInterface.java
+++ b/src/main/java/org/caosdb/server/filesystem/FileSystemInterface.java
@@ -10,16 +10,6 @@ import org.caosdb.server.utils.Undoable;
  */
 public interface FileSystemInterface {
 
-  /**
-   * Store the file described by the FileDescriptorInterface.
-   *
-   * @param file
-   * @return an {@link Undoable} object, which reverts the storage procedure and puts the file back
-   *     to where it was. To be called when failures occured and the transaction needs to roll back.
-   * @throws Message
-   */
-  public abstract Undoable store(RealFSODescriptorInterface file) throws Message;
-
   /**
    * Delete the file described by the FileDescriptorInterface.
    *
diff --git a/src/main/java/org/caosdb/server/filesystem/LocalFileStorage.java b/src/main/java/org/caosdb/server/filesystem/LocalFileStorage.java
index e981071cd7fa83d50e5cdd18d07a49292904ee24..54fb698029048939851aa89719c7d6a8f2f2a10c 100644
--- a/src/main/java/org/caosdb/server/filesystem/LocalFileStorage.java
+++ b/src/main/java/org/caosdb/server/filesystem/LocalFileStorage.java
@@ -285,10 +285,17 @@ public abstract class LocalFileStorage implements FileStorageInterface {
   }
 
   @Override
-  public Undoable move(final RealFSODescriptorInterface file, String key) throws Message {
+  public Undoable move(final RealFSODescriptorInterface file, VirtualFSODescriptorInterface target)
+      throws Message {
+    String key = target.getKey();
+    if (key == null) {
+      key = target.getPath().toString();
+      target.setKey(key);
+    }
+
     final Path targetPath = getRoot().resolve(key);
 
-    if (file.getObjectType() == ObjectType.DIRECTORY) {
+    if (target.getObjectType() == ObjectType.DIRECTORY) {
       final File newDirectory = createDirs(targetPath.toFile());
       return new Undoable() {
 
@@ -319,7 +326,7 @@ public abstract class LocalFileStorage implements FileStorageInterface {
   public Undoable delete(final String fileKey) throws Message {
     final Path targetPath = getRoot().resolve(fileKey);
 
-    return deleteWithEmptyParentDir(targetPath.toFile(), true);
+    return delete(targetPath.toFile(), true);
   }
 
   public Path getRoot() {
@@ -613,17 +620,6 @@ public abstract class LocalFileStorage implements FileStorageInterface {
     };
   }
 
-  Undoable deleteWithEmptyParentDir(final File f, final boolean recursive) throws Message {
-    final File parent = f.getParentFile();
-    if (!getRoot().toFile().equals(parent)) {
-      final File[] siblings = parent.listFiles();
-      if (siblings == null || siblings.length == 1 && siblings[0].equals(f)) {
-        return deleteWithEmptyParentDir(parent, recursive);
-      }
-    }
-    return delete(f, recursive);
-  }
-
   public Long getSize(String key) {
     File file = getFile(key);
     if (file == null) {
diff --git a/src/main/java/org/caosdb/server/filesystem/VirtualFSODescriptorInterface.java b/src/main/java/org/caosdb/server/filesystem/VirtualFSODescriptorInterface.java
index 6b1e8e1eb75c544c843efb02ac03e796540eb790..fa5cf556311ab41d6cd60527dfbfbf53d0c3b9fb 100644
--- a/src/main/java/org/caosdb/server/filesystem/VirtualFSODescriptorInterface.java
+++ b/src/main/java/org/caosdb/server/filesystem/VirtualFSODescriptorInterface.java
@@ -120,4 +120,6 @@ public interface VirtualFSODescriptorInterface extends FSODescriptorInterface {
 
   @Override
   public abstract List<? extends VirtualFSODescriptorInterface> listChildren();
+
+  public abstract void setKey(String key);
 }
diff --git a/src/main/java/org/caosdb/server/jobs/core/AutoCreateDirs.java b/src/main/java/org/caosdb/server/jobs/core/AutoCreateDirs.java
new file mode 100644
index 0000000000000000000000000000000000000000..afbadcbedac4c9f1c0a79f81a7e88b0eddf13678
--- /dev/null
+++ b/src/main/java/org/caosdb/server/jobs/core/AutoCreateDirs.java
@@ -0,0 +1,82 @@
+package org.caosdb.server.jobs.core;
+
+import org.caosdb.server.database.backend.transaction.GetFileEntityByPath;
+import org.caosdb.server.database.exceptions.EntityDoesNotExistException;
+import org.caosdb.server.entity.EntityInterface;
+import org.caosdb.server.entity.InsertEntity;
+import org.caosdb.server.entity.MagicTypes;
+import org.caosdb.server.entity.Role;
+import org.caosdb.server.entity.UpdateEntity;
+import org.caosdb.server.filesystem.FSODescriptor;
+import org.caosdb.server.filesystem.Path;
+import org.caosdb.server.filesystem.VirtualFSODescriptorInterface;
+import org.caosdb.server.jobs.EntityFlagJob;
+import org.caosdb.server.jobs.JobAnnotation;
+import org.caosdb.server.permissions.EntityACL;
+
+@JobAnnotation(flag = "autoCreateDirs", defaultValue = "true", loadAlways = true)
+public class AutoCreateDirs extends EntityFlagJob {
+
+  @Override
+  protected void job(final String value) {
+    final boolean createDirs = "true".equalsIgnoreCase(value);
+
+    if (createDirs
+        && (getEntity() instanceof InsertEntity || getEntity() instanceof UpdateEntity)
+        && getEntity().hasFSODescriptor()) {
+      createDirs(getEntity().getFSODescriptor());
+    }
+  }
+
+  private void createDirs(final VirtualFSODescriptorInterface fso) {
+    VirtualFSODescriptorInterface nextFSO = fso;
+    String fileStorageId = nextFSO.getFileStorageId();
+    Path parentDir = nextFSO.getPath().getParent();
+    while (parentDir != null) {
+      final VirtualFSODescriptorInterface parentFSO = exists(parentDir);
+      if (parentFSO != null) {
+        // the parent does exist.
+        fso.setParentDirectory(parentFSO.getEntityId());
+        break;
+      }
+      nextFSO = createDir(fileStorageId, parentDir, nextFSO);
+      parentDir = parentDir.getParent();
+    }
+    if (parentDir == null) { // root of file system
+      nextFSO.setParentDirectory(MagicTypes.ROOT_DIRECTORY.getId());
+    }
+  }
+
+  private VirtualFSODescriptorInterface exists(final Path dirPath) {
+    for (final EntityInterface e : getContainer()) {
+      if (e.getRole() == Role.Directory
+          && (e instanceof InsertEntity || e instanceof UpdateEntity)
+          && e.getFSODescriptor().getPath().equals(dirPath)) {
+        // Found the directory in the container
+        return e.getFSODescriptor();
+      }
+    }
+    final GetFileEntityByPath t = new GetFileEntityByPath(dirPath);
+    try {
+      execute(t);
+      return t.getEntity().getFSODescriptor();
+    } catch (final EntityDoesNotExistException e) {
+      return null;
+    }
+  }
+
+  private VirtualFSODescriptorInterface createDir(
+      final String fileStorageId, final Path dirPath, final VirtualFSODescriptorInterface child) {
+    final String name = dirPath.getLastSegment();
+    final VirtualFSODescriptorInterface newFD = FSODescriptor.createDir(fileStorageId, dirPath);
+
+    child.setParentDirectory(newFD.getEntityId());
+
+    final EntityInterface newDir = new InsertEntity(name, Role.Directory);
+    newDir.setEntityACL(EntityACL.getOwnerACLFor(getUser()));
+    newDir.setFSODescriptor(newFD);
+    getContainer().add(newDir);
+
+    return newFD;
+  }
+}
diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckFileStorageConsistency.java b/src/main/java/org/caosdb/server/jobs/core/CheckFileStorageConsistency.java
index bd6b42d202f7b6acbc7bf16aba37d753fb219007..8cc5d26efa604b91e2fdafd57935307193980560 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckFileStorageConsistency.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckFileStorageConsistency.java
@@ -38,6 +38,7 @@ import org.caosdb.server.database.exceptions.TransactionException;
 import org.caosdb.server.entity.Message;
 import org.caosdb.server.entity.Message.MessageType;
 import org.caosdb.server.entity.xml.ToElementable;
+import org.caosdb.server.filesystem.FSODescriptor;
 import org.caosdb.server.filesystem.FileSystem;
 import org.caosdb.server.filesystem.Path;
 import org.caosdb.server.filesystem.RealFSODescriptorInterface;
@@ -187,7 +188,8 @@ public class CheckFileStorageConsistency extends FlagJob {
         if (f1 == null) {
           return;
         }
-        Undoable undo1 = FileSystem.getInstance().getFileStorage(f1).move(f1, "somewhere.else");
+        FSODescriptor target = new FSODescriptor(new Path("debug/somewhere.else"));
+        Undoable undo1 = FileSystem.getInstance().getFileStorage(f1).move(f1, target);
 
         getTransaction()
             .acceptObserver(
diff --git a/src/main/java/org/caosdb/server/query/CQLLexer.g4 b/src/main/java/org/caosdb/server/query/CQLLexer.g4
index 99c9879de7a772c6032decc51486fe7485d869e5..1b113a275ab5bbaa75dde3bb689fb2b1f81e60f1 100644
--- a/src/main/java/org/caosdb/server/query/CQLLexer.g4
+++ b/src/main/java/org/caosdb/server/query/CQLLexer.g4
@@ -343,6 +343,10 @@ FILE:
     [Ff][Ii][Ll][Ee]([Ss])? WHITE_SPACE_f?
 ;
 
+DIRECTORY:
+	[Dd][Ii][Rr][Ee][Cc][Tt][Oo][Rr]([Yy]|[Ii][Ee][Ss]) WHITE_SPACE_f?
+;
+
 ENTITY:
     [Ee][Nn][Tt][Ii][Tt]([Yy]|[Ii][Ee][Ss]) WHITE_SPACE_f?
 ;
diff --git a/src/main/java/org/caosdb/server/query/CQLParser.g4 b/src/main/java/org/caosdb/server/query/CQLParser.g4
index d44674b29d5c35fab2db9f4a8395e064219b79c9..a9656ca1ced8055e3915bb81cdaa566988a2bf92 100644
--- a/src/main/java/org/caosdb/server/query/CQLParser.g4
+++ b/src/main/java/org/caosdb/server/query/CQLParser.g4
@@ -99,6 +99,7 @@ role returns [Query.Role r]:
     | RECORD {$r = Query.Role.RECORD;}
     | PROPERTY {$r = Query.Role.PROPERTY;}
     | FILE {$r = Query.Role.FILE;}
+    | DIRECTORY {$r = Query.Role.DIRECTORY;}
     | QUERYTEMPLATE {$r = Query.Role.QUERYTEMPLATE;}
     | ENTITY {$r = Query.Role.ENTITY;}
 ;
diff --git a/src/main/java/org/caosdb/server/query/Query.java b/src/main/java/org/caosdb/server/query/Query.java
index 88da39bce24f1cabf651eebf1532cab14bddb82c..ac1a41a254501f895e81a1764c048850f268fcbf 100644
--- a/src/main/java/org/caosdb/server/query/Query.java
+++ b/src/main/java/org/caosdb/server/query/Query.java
@@ -160,6 +160,7 @@ public class Query implements QueryInterface, ToElementable, TransactionInterfac
     PROPERTY,
     ENTITY,
     FILE,
+    DIRECTORY,
     QUERYTEMPLATE
   }