diff --git a/Modules/include/MicroDAQ.h b/Modules/include/MicroDAQ.h
index b436de18c591190e3de8b3f8776a62845e7fb062..4444c77fc7fea3932dbedcfdde4abb8c9d414609 100644
--- a/Modules/include/MicroDAQ.h
+++ b/Modules/include/MicroDAQ.h
@@ -52,7 +52,7 @@ namespace ChimeraTK {
                 {"MicroDAQ.CONFIG"}};
 
       /** Add a Module as a source to this DAQ. */
-      void addSource(const Module &source, const std::string &namePrefix="");
+      void addSource(const Module &source, const RegisterPath &namePrefix="");
 
     protected:
 
@@ -61,6 +61,9 @@ namespace ChimeraTK {
       template<typename UserType>
       VariableNetworkNode getAccessor(const std::string &variableName);
 
+      /** Map of VariableGroups required to build the hierarchies. The key it the full path name. */
+      std::map<std::string, VariableGroup> groupMap;
+
       /** boost::fusion::map of UserTypes to std::lists containing the ArrayPollInput accessors. These accessors are
       *  dynamically created by the AccessorAttacher. */
       template<typename UserType>
diff --git a/Modules/src/MicroDAQ.cc b/Modules/src/MicroDAQ.cc
index 348b7afc81b19e190327cea2eeb20980a3d1e3ff..a6e26c9e5754690cbb56414268a5837c64fb64df 100644
--- a/Modules/src/MicroDAQ.cc
+++ b/Modules/src/MicroDAQ.cc
@@ -39,20 +39,40 @@ namespace ChimeraTK {
 
   /*********************************************************************************************************************/
 
-  void MicroDAQ::addSource(const Module &source, const std::string &namePrefix) {
+  void MicroDAQ::addSource(const Module &source, const RegisterPath &namePrefix) {
 
     // for simplification, first create a VirtualModule containing the correct hierarchy structure (obeying eliminate
     // hierarchy etc.)
     auto dynamicModel = source.findTag(".*");     /// @todo use virtualise() instead
 
+    // create variable group map for namePrefix if needed
+    if(groupMap.find(namePrefix) == groupMap.end()) {
+      // search for existing parent (if any)
+      auto parentPrefix = namePrefix;
+      while(groupMap.find(parentPrefix) == groupMap.end()) {
+        if(parentPrefix == "/") break;  // no existing parent found
+        parentPrefix = std::string(parentPrefix).substr(0,std::string(parentPrefix).find_last_of("/"));
+      }
+      // create all not-yet-existing parents
+      while(parentPrefix != namePrefix) {
+        EntityOwner *owner = this;
+        if(parentPrefix != "/") owner = &groupMap[parentPrefix];
+        auto stop = std::string(namePrefix).find_first_of("/", parentPrefix.length()+1);
+        if(stop == std::string::npos) stop = namePrefix.length();
+        RegisterPath name = std::string(namePrefix).substr(parentPrefix.length(),stop-parentPrefix.length());
+        parentPrefix /= name;
+        groupMap[parentPrefix] = VariableGroup(owner, std::string(name).substr(1), "");
+      }
+    }
+
     // add all accessors on this hierarchy level
     for(auto &acc : dynamicModel.getAccessorList()) {
-      boost::fusion::for_each(accessorListMap.table, detail::AccessorAttacher(acc, this, namePrefix+"/"+acc.getName()));
+      boost::fusion::for_each(accessorListMap.table, detail::AccessorAttacher(acc, this, namePrefix/acc.getName()));
     }
 
     // recurse into submodules
     for(auto mod : dynamicModel.getSubmoduleList()) {
-      addSource(*mod, namePrefix+"/"+mod->getName());
+      addSource(*mod, namePrefix/mod->getName());
     }
 
   }
@@ -74,7 +94,9 @@ namespace ChimeraTK {
     // add accessor and name to lists
     auto &accessorList = boost::fusion::at_key<UserType>(accessorListMap.table);
     auto &nameList = boost::fusion::at_key<UserType>(nameListMap.table);
-    accessorList.emplace_back(this, variableName, "", 0, "");
+    auto dirName = variableName.substr(0,variableName.find_last_of("/"));
+    auto baseName = variableName.substr(variableName.find_last_of("/")+1);
+    accessorList.emplace_back(&groupMap[dirName], baseName, "", 0, "");
     nameList.push_back(variableName);
 
     // return the accessor
diff --git a/include/ArrayAccessor.h b/include/ArrayAccessor.h
index 9cde8e1b040c42d4b1dff1072c8400a68b15e311..262b1c11fe10a7d86d172eca356410460dd59816 100644
--- a/include/ArrayAccessor.h
+++ b/include/ArrayAccessor.h
@@ -54,7 +54,7 @@ namespace ChimeraTK {
         return dataLoss;
       }
 
-  protected:
+    protected:
 
       friend class InversionOfControlAccessor<ArrayAccessor<UserType>>;
 
diff --git a/include/InversionOfControlAccessor.h b/include/InversionOfControlAccessor.h
index 4c62db2f7d800378b46d095d58a17286cc9028d8..21b6f4fefb78124244aa36594a01e7ea6ccaa30c 100644
--- a/include/InversionOfControlAccessor.h
+++ b/include/InversionOfControlAccessor.h
@@ -96,6 +96,10 @@ namespace ChimeraTK {
       {
         static_assert(std::is_base_of<InversionOfControlAccessor<Derived>, Derived>::value,
                       "InversionOfControlAccessor<> must be used in a curiously recurring template pattern!");
+        if(name.find_first_of("/") != std::string::npos) {
+          throw ChimeraTK::logic_error("Accessor names must not contain slashes: '"+name+"' in module '"
+                                       +owner->getQualifiedName()+"'.");
+        }
         owner->registerAccessor(node);
       }
 
diff --git a/include/VirtualModule.h b/include/VirtualModule.h
index ae8e873e1a5762b66f666073188fd9eaaa9513c7..80624011882f681608ec72a268b1640f1b61e37a 100644
--- a/include/VirtualModule.h
+++ b/include/VirtualModule.h
@@ -12,6 +12,7 @@
 
 #include <boost/thread.hpp>
 
+#include <ChimeraTK/RegisterPath.h>
 #include "Module.h"
 
 namespace ChimeraTK {
@@ -24,7 +25,11 @@ namespace ChimeraTK {
       /** Constructor */
       VirtualModule(const std::string &name, const std::string &description, ModuleType moduleType)
       : Module(nullptr, name, description), _moduleType(moduleType)
-      {}
+      {
+        if(name.find_first_of("/") != std::string::npos) {
+          throw ChimeraTK::logic_error("Module names must not contain slashes: '"+name+"'.");
+        }
+      }
 
       /** Copy constructor */
       VirtualModule(const VirtualModule &other);
@@ -45,11 +50,11 @@ namespace ChimeraTK {
       void addSubModule(VirtualModule module);
 
       /** Return the submodule with the given name. If it doesn't exist, create it first. */
-      VirtualModule& createAndGetSubmodule(const std::string& moduleName);
+      VirtualModule& createAndGetSubmodule(const RegisterPath& moduleName);
 
       /** Like createAndGetSubmodule(), but recursively create a hierarchy of submodules separated by "/" in the
        *  moduleName. */
-      VirtualModule& createAndGetSubmoduleRecursive(const std::string& moduleName);
+      VirtualModule& createAndGetSubmoduleRecursive(const RegisterPath& moduleName);
 
       ModuleType getModuleType() const override { return _moduleType; }
 
diff --git a/src/ApplicationModule.cc b/src/ApplicationModule.cc
index d489935dcf3c9d8544eef9f49063a03926b12e38..e9330c635a9581334211eb66ea38564a3583ad37 100644
--- a/src/ApplicationModule.cc
+++ b/src/ApplicationModule.cc
@@ -18,6 +18,10 @@ namespace ChimeraTK {
     if(!dynamic_cast<ModuleGroup*>(owner) && !dynamic_cast<Application*>(owner)) {
       throw ChimeraTK::logic_error("ApplicationModules must be owned either by ModuleGroups or the Application!");
     }
+    if(name.find_first_of("/") != std::string::npos) {
+      throw ChimeraTK::logic_error("Module names must not contain slashes: '"+name+" owned by '"
+                                   +owner->getQualifiedName()+"'.");
+    }
   }
 
 /*********************************************************************************************************************/
diff --git a/src/ControlSystemModule.cc b/src/ControlSystemModule.cc
index 7ad6402083ed87c7b9cd1489b2b84c701c007610..1ffcb3fe6ef76725f969d96ff3bdbaf86f68f702 100644
--- a/src/ControlSystemModule.cc
+++ b/src/ControlSystemModule.cc
@@ -11,7 +11,10 @@
 namespace ChimeraTK {
 
   ControlSystemModule::ControlSystemModule(const std::string& _variableNamePrefix)
-  : Module(&(Application::getInstance()), "ControlSystem:"+_variableNamePrefix, ""),
+    : Module(&(Application::getInstance()),
+             _variableNamePrefix.empty() ? "<ControlSystem>"
+               : _variableNamePrefix.substr(_variableNamePrefix.find_last_of("/")+1),
+             ""),
     variableNamePrefix(_variableNamePrefix)
   {}
 
@@ -19,6 +22,7 @@ namespace ChimeraTK {
 
   VariableNetworkNode ControlSystemModule::operator()(const std::string& variableName, const std::type_info &valueType,
                                                       size_t nElements) const {
+    assert(variableName.find_first_of("/") == std::string::npos);
     if(variables.count(variableName) == 0) {
       variables[variableName] = {variableNamePrefix/variableName, VariableDirection::invalid, valueType, nElements};
     }
@@ -28,6 +32,7 @@ namespace ChimeraTK {
   /*********************************************************************************************************************/
 
   Module& ControlSystemModule::operator[](const std::string& moduleName) const {
+    assert(moduleName.find_first_of("/") == std::string::npos);
     if(subModules.count(moduleName) == 0) {
       subModules[moduleName] = {variableNamePrefix/moduleName};
     }
diff --git a/src/DeviceModule.cc b/src/DeviceModule.cc
index 6d8fb8ee37f923ca2a635a8036a48593c58282a7..6d5acf5d3f692ce522c8f9dfb18d458b4c869ef8 100644
--- a/src/DeviceModule.cc
+++ b/src/DeviceModule.cc
@@ -14,7 +14,10 @@
 namespace ChimeraTK {
 
   DeviceModule::DeviceModule(const std::string& _deviceAliasOrURI, const std::string& _registerNamePrefix)
-  : Module(&(Application::getInstance()), "Device:"+_deviceAliasOrURI+":"+_registerNamePrefix, ""),
+  : Module(&(Application::getInstance()),
+           _registerNamePrefix.empty() ? "<Device:"+_deviceAliasOrURI+">"
+             : _registerNamePrefix.substr(_registerNamePrefix.find_last_of("/")+1),
+           ""),
     deviceAliasOrURI(_deviceAliasOrURI),
     registerNamePrefix(_registerNamePrefix)
   {}
diff --git a/src/VirtualModule.cc b/src/VirtualModule.cc
index abf10f30f2796bf79a0fd6a701345f1480939eea..04daef2e1dec9aa110b53ac6197510b481b80adc 100644
--- a/src/VirtualModule.cc
+++ b/src/VirtualModule.cc
@@ -109,24 +109,24 @@ namespace ChimeraTK {
 
 /*********************************************************************************************************************/
 
-  VirtualModule& VirtualModule::createAndGetSubmodule(const std::string& moduleName) {
+  VirtualModule& VirtualModule::createAndGetSubmodule(const RegisterPath& moduleName) {
     for(auto &sm : submodules) {
-      if(sm.getName() == moduleName) return sm;
+      if(moduleName == sm.getName()) return sm;
     }
-    addSubModule(VirtualModule(moduleName, getDescription(), getModuleType()));
+    addSubModule(VirtualModule(std::string(moduleName).substr(1), getDescription(), getModuleType()));
     return submodules.back();
   }
 
 /*********************************************************************************************************************/
 
-  VirtualModule& VirtualModule::createAndGetSubmoduleRecursive(const std::string& moduleName) {
-    auto slash = moduleName.find_first_of("/");
+  VirtualModule& VirtualModule::createAndGetSubmoduleRecursive(const RegisterPath& moduleName) {
+    auto slash = std::string(moduleName).find_first_of("/",1);
     if(slash == std::string::npos) {
       return createAndGetSubmodule(moduleName);
     }
     else {
-      auto firstSubmodule = moduleName.substr(0,slash);
-      auto remainingSubmodules = moduleName.substr(slash+1);
+      auto firstSubmodule = std::string(moduleName).substr(0,slash);
+      auto remainingSubmodules = std::string(moduleName).substr(slash+1);
       return createAndGetSubmodule(firstSubmodule).createAndGetSubmoduleRecursive(remainingSubmodules);
     }
   }