diff --git a/source/RobotAPI/components/ObjectPoseObserver/ObjectPose.cpp b/source/RobotAPI/components/ObjectPoseObserver/ObjectPose.cpp
index 0289d37380d714ea71f0b427e2504c40fd31eed7..ae8531edacea24b495fac67c39fd50f51a927835 100644
--- a/source/RobotAPI/components/ObjectPoseObserver/ObjectPose.cpp
+++ b/source/RobotAPI/components/ObjectPoseObserver/ObjectPose.cpp
@@ -45,7 +45,7 @@ namespace armarx::objpose
     {
         providerName = ice.providerName;
         objectType = ice.objectType;
-        objectID = { ice.objectID.dataset, ice.objectID.name };
+        objectID = { ice.objectID.dataset, ice.objectID.className, ice.objectID.instanceName };
 
         objectPoseRobot = armarx::objpose::toEigen(ice.objectPoseRobot);
         objectPoseGlobal = armarx::objpose::toEigen(ice.objectPoseGlobal);
@@ -72,7 +72,7 @@ namespace armarx::objpose
     {
         ice.providerName = providerName;
         ice.objectType = objectType;
-        ice.objectID = { objectID.dataset(), objectID.name() };
+        ice.objectID = { objectID.dataset(), objectID.className(), objectID.instanceName() };
 
         ice.objectPoseRobot = new Pose(objectPoseRobot);
         ice.objectPoseGlobal = new Pose(objectPoseGlobal);
@@ -93,7 +93,7 @@ namespace armarx::objpose
         providerName = provided.providerName;
         objectType = provided.objectType;
 
-        objectID = { provided.objectID.dataset, provided.objectID.name };
+        objectID = { provided.objectID.dataset, provided.objectID.className, provided.objectID.instanceName };
 
         objectPoseOriginal = armarx::objpose::toEigen(provided.objectPose);
         objectPoseOriginalFrame = provided.objectPoseFrame;
diff --git a/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.cpp b/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.cpp
index f7d2eee97b3ec601420ce9cf010af23817814dd7..9343a88d5589a19d832eadfdca2c4125494e226d 100644
--- a/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.cpp
+++ b/source/RobotAPI/components/ObjectPoseObserver/ObjectPoseObserver.cpp
@@ -152,10 +152,18 @@ namespace armarx
                 robotNode->setJointValue(value + calibration.offset);
             }
 
-            for (const auto& provided : providedPoses)
+            for (const objpose::data::ProvidedObjectPose& provided : providedPoses)
             {
                 objpose::ObjectPose& pose = objectPoses.emplace_back();
                 pose.fromProvidedPose(provided, robot);
+                if (pose.objectID.dataset().empty())
+                {
+                    // Try to find the data set. (It might be good to cache this.)
+                    if (std::optional<ObjectInfo> objectInfo = objectFinder.findObject(pose.objectID))
+                    {
+                        pose.objectID = { objectInfo->dataset(), pose.objectID.className(), pose.objectID.instanceName() };
+                    }
+                }
                 if (!(provided.localOOBB.position && provided.localOOBB.orientation && provided.localOOBB.extents))
                 {
                     pose.localOOBB = getObjectOOBB(pose.objectID);
diff --git a/source/RobotAPI/components/ObjectPoseObserver/ice_conversions.cpp b/source/RobotAPI/components/ObjectPoseObserver/ice_conversions.cpp
index 506fc289280788d783f46455ead20a2ded115454..994298d38c47faace57a85e6c4e87e169ecbeb45 100644
--- a/source/RobotAPI/components/ObjectPoseObserver/ice_conversions.cpp
+++ b/source/RobotAPI/components/ObjectPoseObserver/ice_conversions.cpp
@@ -35,14 +35,14 @@ namespace armarx
     }
 
 
-    std::string objpose::getID(const ObjectID& id)
-    {
-        return id.dataset + "/" + id.name;
-    }
-
     std::ostream& objpose::operator<<(std::ostream& os, const ObjectID& id)
     {
-        return os << "'" << id.dataset << "/" << id.name << "'";
+        os << "'" << id.dataset << "/" << id.className;
+        if (!id.instanceName.empty())
+        {
+            os << "/" << id.instanceName;
+        }
+        return os << "'";
     }
 
     const simox::meta::EnumNames<objpose::ObjectTypeEnum> objpose::ObjectTypeEnumNames =
diff --git a/source/RobotAPI/components/ObjectPoseObserver/ice_conversions.h b/source/RobotAPI/components/ObjectPoseObserver/ice_conversions.h
index b459a01cd9a7411cdbbb1c32dc2a15394c0dee25..83f9b43edb246bfaf7c0b748dfac1f2b0721726e 100644
--- a/source/RobotAPI/components/ObjectPoseObserver/ice_conversions.h
+++ b/source/RobotAPI/components/ObjectPoseObserver/ice_conversions.h
@@ -19,7 +19,6 @@ namespace simox
 namespace armarx::objpose
 {
 
-    std::string getID(const ObjectID& id);
     std::ostream& operator<<(std::ostream& os, const ObjectID& id);
 
     extern const simox::meta::EnumNames<objpose::ObjectTypeEnum> ObjectTypeEnumNames;
diff --git a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp
index 37c660527f62b0e50549e6297ec9d31fc06ab350..e4fa766c3249b699f65fe1105977626adbd22b10 100644
--- a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp
@@ -30,6 +30,9 @@
 #include <QMessageBox>
 #include <QTimer>
 
+#define ENABLE_INTROSPECTION 0
+
+
 namespace armarx
 {
     struct ArVizWidgetBatchCallback : IceUtil::Shared
@@ -85,7 +88,7 @@ namespace armarx
         // Layer info tree.
 
         connect(widget.layerTree, &QTreeWidget::currentItemChanged, this, &This::updateSelectedLayer);
-#if 0
+#if ENABLE_INTROSPECTION
         connect(widget.defaultShowLimitSpinBox, qOverload<int>(&QSpinBox::valueChanged),
                 &layerInfoTree, &LayerInfoTree::setMaxElementCountDefault);
         layerInfoTree.setMaxElementCountDefault(widget.defaultShowLimitSpinBox->value());
@@ -291,7 +294,7 @@ namespace armarx
 
     void ArVizWidgetController::updateSelectedLayer(QTreeWidgetItem* current, QTreeWidgetItem* previous)
     {
-#if 0
+#if ENABLE_INTROSPECTION
         (void) previous;
 
         if (!current->parent())
diff --git a/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp b/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp
index 816e797f42714e8da58658d7bde649241fac6cf8..9c97a261eec0c4aadb303ac8e2f61607202bbf75 100644
--- a/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/ObjectPoseGui/ObjectPoseGuiWidgetController.cpp
@@ -37,7 +37,7 @@ namespace armarx
     {
         widget.setupUi(getWidget());
 
-        QStringList header = {"Dataset", "Name", "Provider", "Type"};
+        QStringList header = {"Dataset", "ClassName", "InstanceName", "Provider", "Type"};
         widget.objectsTable->setColumnCount(header.size());
         widget.objectsTable->setHorizontalHeaderLabels(header);
 
@@ -128,7 +128,9 @@ namespace armarx
             widget.objectsTable->setItem(
                 i, col++, new QTableWidgetItem(pose.objectID.dataset.c_str()));
             widget.objectsTable->setItem(
-                i, col++, new QTableWidgetItem(pose.objectID.name.c_str()));
+                i, col++, new QTableWidgetItem(pose.objectID.className.c_str()));
+            widget.objectsTable->setItem(
+                i, col++, new QTableWidgetItem(pose.objectID.instanceName.c_str()));
             widget.objectsTable->setItem(
                 i, col++, new QTableWidgetItem(pose.providerName.c_str()));
             widget.objectsTable->setItem(
diff --git a/source/RobotAPI/interface/objectpose/types.ice b/source/RobotAPI/interface/objectpose/types.ice
index eaf7adf779b0ac6d51c952f343f08d75bd87d93c..097c6890165ed7c943630cc845b5bceb73c1294c 100644
--- a/source/RobotAPI/interface/objectpose/types.ice
+++ b/source/RobotAPI/interface/objectpose/types.ice
@@ -38,8 +38,12 @@ module armarx
 
         struct ObjectID
         {
-            string dataset;  ///< e.g. "KIT", "YCB", "SecondHands", ...
-            string name;     ///< e.g. "Amicelli", "001_chips_can", ...
+            /// The dataset name in ArmarXObjects, e.g. "KIT", "YCB", "SecondHands", ...
+            string dataset;
+            /// The class name in ArmarXObjects, e.g. "Amicelli", "001_chips_can", ...
+            string className;
+            /// An optional instance name, chosen by the provider.
+            string instanceName;
         };
         sequence<ObjectID> ObjectIDSeq;
 
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.cpp b/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.cpp
index 28634f811f1147c77dbe04271165ae4d86f45aec..a02b6bd1031836da23ce9617e7e5f55d7075d2d3 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectFinder.cpp
@@ -71,7 +71,7 @@ namespace armarx
 
     std::optional<ObjectInfo> ObjectFinder::findObject(const ObjectID& id) const
     {
-        return findObject(id.dataset(), id.name());
+        return findObject(id.dataset(), id.className());
     }
 
     std::vector<std::string> ObjectFinder::getDatasets() const
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectID.cpp b/source/RobotAPI/libraries/ArmarXObjects/ObjectID.cpp
index f24af1a926487d44b5efca3135813ddf70416ceb..796c658992a1db36d884ff3f510fa994dc5bc80c 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectID.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectID.cpp
@@ -1,7 +1,7 @@
 #include "ObjectID.h"
 
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
-#include <ArmarXCore/core/util/StringHelpers.h>
+#include <SimoxUtility/algorithm/string/string_tools.h>
 
 
 namespace armarx
@@ -10,8 +10,8 @@ namespace armarx
     {
     }
 
-    ObjectID::ObjectID(const std::string& dataset, const std::string& name) :
-        _dataset(dataset), _name(name)
+    ObjectID::ObjectID(const std::string& dataset, const std::string& className, const std::string& instancName) :
+        _dataset(dataset), _className(className), _instanceName(instancName)
     {
     }
 
@@ -19,28 +19,50 @@ namespace armarx
     {
         if (nameOrID.find("/") != nameOrID.npos)
         {
-            const std::vector<std::string> split = armarx::split(nameOrID, "/", true);
-            ARMARX_CHECK_EQUAL(split.size(), 2) << "Expected ID of format 'Dataset/Name', but got: '" << nameOrID
-                                                << "' (too many '/').";
+            const std::vector<std::string> split = simox::alg::split(nameOrID, "/", true);
+            ARMARX_CHECK(split.size() == 2 || split.size() == 3)
+                    << "Expected ID of format 'Dataset/ClassName' or 'Dataset/ClassName/InstanceName'"
+                    << ", but got: '" << nameOrID << "' (too many '/').";
             _dataset = split[0];
-            _name = split[1];
+            _className = split[1];
         }
         else
         {
             // dataset is left empty.
-            _name = nameOrID;
+            _className = nameOrID;
         }
     }
 
+    std::string ObjectID::str() const
+    {
+        std::string _str = _dataset + "/" + _className;
+        if (!_instanceName.empty())
+        {
+            _str += "/" + _instanceName;
+        }
+        return _str;
+    }
+
     bool ObjectID::operator==(const ObjectID& rhs) const
     {
-        return _name == rhs._name && _dataset == rhs._dataset;
+        return _className == rhs._className
+               && _dataset == rhs._dataset
+               && _instanceName == rhs._instanceName;
     }
 
     bool ObjectID::operator<(const ObjectID& rhs) const
     {
-        return _dataset < rhs._dataset
-               || (_dataset == rhs._dataset && _name < rhs._name);
+        if (_dataset != rhs._dataset)
+        {
+            return _dataset < rhs._dataset;
+        }
+        // equal dataset
+        if (_className != rhs._className)
+        {
+            return _className < rhs._className;
+        }
+        // equal class name
+        return _instanceName < rhs._instanceName;
     }
 
 }
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectID.h b/source/RobotAPI/libraries/ArmarXObjects/ObjectID.h
index 437bbaa88e3de76657c42cd52e68799896c53e17..263af5ae61d673a945c401cc344c1d6630e279b5 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectID.h
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectID.h
@@ -6,32 +6,35 @@
 namespace armarx
 {
     /**
-     * @brief A known object ID of the form "Dataset/Name".
+     * @brief A known object ID of the form "Dataset/ClassName" or "Dataset/ClassName/InstanceName".
      */
     class ObjectID
     {
     public:
 
         ObjectID();
-        ObjectID(const std::string& dataset, const std::string& name);
-        /// Construct from either a name ("myobject") or ID ("mydataset/myobject").
+        ObjectID(const std::string& dataset, const std::string& className, const std::string& instancName = "");
+        /// Construct from either a name ("myobject") or ID ("mydataset/myobject", "mydataset/myclass/myinstance").
         ObjectID(const std::string& nameOrID);
 
 
-        std::string dataset() const
+        inline std::string dataset() const
         {
             return _dataset;
         }
-        std::string name() const
+        inline std::string className() const
         {
-            return _name;
+            return _className;
         }
-        /// Return "dataset/name".
-        std::string str() const
+        inline std::string instanceName() const
         {
-            return _dataset + "/" + _name;
+            return _instanceName;
         }
 
+        /// Return "dataset/className" or "dataset/className/instanceName".
+        std::string str() const;
+
+
         bool operator==(const ObjectID& rhs) const;
         inline bool operator!=(const ObjectID& rhs) const
         {
@@ -54,8 +57,12 @@ namespace armarx
 
     private:
 
+        /// The dataset name in ArmarXObjects, e.g. "KIT", "YCB", "SecondHands", ...
         std::string _dataset;
-        std::string _name;
+        /// The class name in ArmarXObjects, e.g. "Amicelli", "001_chips_can", ...
+        std::string _className;
+        /// An optional instance name, chosen by the user.
+        std::string _instanceName;
 
     };
 
diff --git a/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.cpp b/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.cpp
index 83f815b7a7cab582b8605119f69aad5a8758e14f..ac272b10abe1bc26e47a52527df38034b2f24905 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/ObjectInfo.cpp
@@ -36,7 +36,7 @@ namespace armarx
 
     std::string ObjectInfo::name() const
     {
-        return _id.name();
+        return _id.className();
     }
 
     ObjectID ObjectInfo::id() const
@@ -51,7 +51,7 @@ namespace armarx
 
     ObjectInfo::path ObjectInfo::objectDirectory() const
     {
-        return path(_packageName) / _id.dataset() / _id.name();
+        return path(_packageName) / _id.dataset() / _id.className();
     }
 
     PackageFileLocation ObjectInfo::file(const std::string& _extension, const std::string& suffix) const
@@ -61,7 +61,7 @@ namespace armarx
         {
             extension = "." + extension;
         }
-        std::string filename = _id.name() + suffix + extension;
+        std::string filename = _id.className() + suffix + extension;
 
         PackageFileLocation loc;
         loc.package = _packageName;