diff --git a/source/RobotAPI/libraries/armem_gui/CMakeLists.txt b/source/RobotAPI/libraries/armem_gui/CMakeLists.txt
index 2a781dd3989d5731393e1b5d9304b06f467611a4..46fce90ac352efc0ed0870d4988fb1eea80dfa0e 100644
--- a/source/RobotAPI/libraries/armem_gui/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem_gui/CMakeLists.txt
@@ -41,6 +41,7 @@ set(SOURCES
     instance/tree_visitors/TreeDataVisitorBase.cpp
     instance/tree_visitors/TreeDataVisitor.cpp
     instance/tree_visitors/TreeTypedDataVisitor.cpp
+    instance/tree_visitors/TreeTypedJSONConverter.cpp
 
     memory/GroupBox.cpp
     memory/TreeWidget.cpp
@@ -81,6 +82,7 @@ set(HEADERS
     instance/tree_visitors/TreeDataVisitorBase.h
     instance/tree_visitors/TreeDataVisitor.h
     instance/tree_visitors/TreeTypedDataVisitor.h
+    instance/tree_visitors/TreeTypedJSONConverter.h
 
     memory/GroupBox.h
     memory/TreeWidget.h
diff --git a/source/RobotAPI/libraries/armem_gui/instance/InstanceView.cpp b/source/RobotAPI/libraries/armem_gui/instance/InstanceView.cpp
index b1f347c46cc32a391212d1cd89c88255f7703aa8..bcfce34f33b01afabf9c65cb897d2c9cd1d9f58b 100644
--- a/source/RobotAPI/libraries/armem_gui/instance/InstanceView.cpp
+++ b/source/RobotAPI/libraries/armem_gui/instance/InstanceView.cpp
@@ -1,4 +1,5 @@
 #include "InstanceView.h"
+#include <new>
 
 #include <QAction>
 #include <QApplication>
@@ -20,7 +21,6 @@
 
 #include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 
-#include <RobotAPI/libraries/aron/converter/json/NLohmannJSONConverter.h>
 #include <RobotAPI/libraries/aron/core/data/variant/complex/NDArray.h>
 #include <RobotAPI/libraries/aron/core/type/variant/container/Object.h>
 
@@ -33,6 +33,7 @@
 #include <RobotAPI/libraries/armem_gui/instance/serialize_path.h>
 #include <RobotAPI/libraries/armem_gui/instance/tree_builders/DataTreeBuilder.h>
 #include <RobotAPI/libraries/armem_gui/instance/tree_builders/TypedDataTreeBuilder.h>
+#include <RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedJSONConverter.h>
 
 #include "MemoryIDTreeWidgetItem.h"
 #include "WidgetsWithToolbar.h"
@@ -429,10 +430,13 @@ namespace armarx::armem::gui::instance
             try
             {
                 aron::data::VariantPtr element = currentInstance->data()->navigateAbsolute(path);
-                nlohmann::json json =
-                    aron::converter::AronNlohmannJSONConverter::ConvertToNlohmannJSON(element);
+                TreeTypedJSONConverter conv;
+                // TODO(phesch): Type hierarchy doesn't match data hierarchy
+                armarx::aron::data::visitRecursive(conv, currentInstance->data(), currentAronType);
+                //nlohmann::json json =
+                //   aron::converter::AronNlohmannJSONConverter::ConvertToNlohmannJSON(element);
                 QClipboard* clipboard = QApplication::clipboard();
-                clipboard->setText(QString::fromStdString(json.dump(2)));
+                clipboard->setText(QString::fromStdString(conv.getJSON().dump(2)));
                 QApplication::processEvents();
             }
             catch (const aron::error::AronException& e)
diff --git a/source/RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedJSONConverter.cpp b/source/RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedJSONConverter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f4cf3788da6cfb911d9dba4ad11b0aea234af1e6
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedJSONConverter.cpp
@@ -0,0 +1,288 @@
+#include "TreeTypedJSONConverter.h"
+
+#include <SimoxUtility/json/eigen_conversion.h>
+
+#include <ArmarXCore/core/logging/Logging.h>
+
+#include "RobotAPI/libraries/aron/core/Exception.h"
+#include <RobotAPI/libraries/armem/core/Time.h>
+#include <RobotAPI/libraries/aron/converter/eigen/EigenConverter.h>
+
+namespace armarx::armem::gui::instance
+{
+    TreeTypedJSONConverter::TreeTypedJSONConverter()
+    {
+        jsonStack.push({"", nlohmann::json()});
+    }
+
+    const nlohmann::json&
+    TreeTypedJSONConverter::getJSON()
+    {
+        nlohmann::json& obj = jsonStack.top().second;
+        if (obj.front().is_object())
+        {
+            return obj.front();
+        }
+        return obj;
+    }
+
+    void
+    TreeTypedJSONConverter::visitObjectOnEnter(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        std::string key = "";
+        try
+        {
+            key = elementData->getPath().getLastElement();
+        }
+        catch (const aron::error::AronException& e)
+        {
+            ARMARX_WARNING << "Object did not have a path." << e.getReason();
+        }
+        jsonStack.push({key, nlohmann::json(nlohmann::json::value_t::object)});
+    }
+
+    void
+    TreeTypedJSONConverter::visitObjectOnExit(DataInput& /*elementData*/,
+                                              TypeInput& /*elementType*/)
+    {
+        auto obj = jsonStack.top();
+        jsonStack.pop();
+        insertIntoJSON(obj.first, obj.second);
+    }
+
+    void
+    TreeTypedJSONConverter::visitDictOnEnter(DataInput& elementData, TypeInput& elementType)
+    {
+        this->visitObjectOnEnter(elementData, elementType);
+    }
+
+    void
+    TreeTypedJSONConverter::visitDictOnExit(DataInput& elementData, TypeInput& elementType)
+    {
+        this->visitObjectOnExit(elementData, elementType);
+    }
+
+    void
+    TreeTypedJSONConverter::visitPairOnEnter(DataInput& elementData, TypeInput& elementType)
+    {
+        this->visitListOnEnter(elementData, elementType);
+    }
+
+    void
+    TreeTypedJSONConverter::visitPairOnExit(DataInput& elementData, TypeInput& elementType)
+    {
+        this->visitListOnExit(elementData, elementType);
+    }
+
+    void
+    TreeTypedJSONConverter::visitTupleOnEnter(DataInput& elementData, TypeInput& elementType)
+    {
+        this->visitListOnEnter(elementData, elementType);
+    }
+
+    void
+    TreeTypedJSONConverter::visitTupleOnExit(DataInput& elementData, TypeInput& elementType)
+    {
+        this->visitListOnExit(elementData, elementType);
+    }
+
+    void
+    TreeTypedJSONConverter::visitListOnEnter(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        jsonStack.push({key, nlohmann::json(nlohmann::json::value_t::array)});
+    }
+
+    void
+    TreeTypedJSONConverter::visitListOnExit(DataInput& /*elementData*/, TypeInput& /*elementType*/)
+    {
+        auto list = jsonStack.top();
+        jsonStack.pop();
+        insertIntoJSON(list.first, list.second);
+    }
+
+    void
+    TreeTypedJSONConverter::visitMatrix(DataInput& elementData, TypeInput& elementType)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        auto nd = *aron::data::NDArray::DynamicCastAndCheck(elementData);
+        auto t = *aron::type::Matrix::DynamicCastAndCheck(elementType);
+        nlohmann::json obj;
+        if (nd.getType() == "float")
+        {
+            Eigen::Map<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic>> m(
+                reinterpret_cast<float*>(nd.getData()), t.getRows(), t.getCols());
+            Eigen::to_json(obj, m);
+        }
+        else if (nd.getType() == "double")
+        {
+            Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>> m(
+                reinterpret_cast<double*>(nd.getData()), t.getRows(), t.getCols());
+            Eigen::to_json(obj, m);
+        }
+        else
+        {
+            obj = handleGenericNDArray(nd);
+        }
+        insertIntoJSON(key, obj);
+    }
+
+    void
+    TreeTypedJSONConverter::visitNDArray(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        auto nd = *aron::data::NDArray::DynamicCastAndCheck(elementData);
+        insertIntoJSON(key, handleGenericNDArray(nd));
+    }
+
+    void
+    TreeTypedJSONConverter::visitQuaternion(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        auto nd = *aron::data::NDArray::DynamicCastAndCheck(elementData);
+        nlohmann::json obj;
+        Eigen::to_json(obj, aron::converter::AronEigenConverter::ConvertToQuaternionf(nd));
+        insertIntoJSON(key, obj);
+    }
+
+    void
+    TreeTypedJSONConverter::visitOrientation(DataInput& elementData, TypeInput& elementType)
+    {
+        this->visitQuaternion(elementData, elementType);
+    }
+
+    void
+    TreeTypedJSONConverter::visitPosition(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        auto nd = *aron::data::NDArray::DynamicCastAndCheck(elementData);
+        nlohmann::json obj;
+        Eigen::to_json(obj, aron::converter::AronEigenConverter::ConvertToVector3f(nd));
+        insertIntoJSON(key, obj);
+    }
+
+    void
+    TreeTypedJSONConverter::visitPose(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        auto nd = *aron::data::NDArray::DynamicCastAndCheck(elementData);
+        nlohmann::json obj;
+        Eigen::to_json(obj, aron::converter::AronEigenConverter::ConvertToMatrix4f(nd));
+        insertIntoJSON(key, obj);
+    }
+
+    void
+    TreeTypedJSONConverter::visitImage(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        auto nd = *aron::data::NDArray::DynamicCastAndCheck(elementData);
+        insertIntoJSON(key, handleGenericNDArray(nd));
+    }
+
+    void
+    TreeTypedJSONConverter::visitPointCloud(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        auto nd = *aron::data::NDArray::DynamicCastAndCheck(elementData);
+        insertIntoJSON(key, handleGenericNDArray(nd));
+    }
+
+    void
+    TreeTypedJSONConverter::visitIntEnum(DataInput& elementData, TypeInput& elementType)
+    {
+        /* Not handled by the TreeTypedDataVisitor either */
+    }
+
+    void
+    TreeTypedJSONConverter::visitInt(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        int i = *aron::data::Int::DynamicCastAndCheck(elementData);
+        insertIntoJSON(key, i);
+    }
+
+    void
+    TreeTypedJSONConverter::visitLong(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        int64_t l = *aron::data::Long::DynamicCastAndCheck(elementData);
+        insertIntoJSON(key, l);
+    }
+
+    void
+    TreeTypedJSONConverter::visitFloat(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        float f = *aron::data::Float::DynamicCastAndCheck(elementData);
+        insertIntoJSON(key, f);
+    }
+
+    void
+    TreeTypedJSONConverter::visitDouble(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        double d = *aron::data::Double::DynamicCastAndCheck(elementData);
+        insertIntoJSON(key, d);
+    }
+
+    void
+    TreeTypedJSONConverter::visitBool(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        bool b = *aron::data::Bool::DynamicCastAndCheck(elementData);
+        insertIntoJSON(key, b);
+    }
+
+    void
+    TreeTypedJSONConverter::visitString(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        std::string s = *aron::data::String::DynamicCastAndCheck(elementData);
+        insertIntoJSON(key, s);
+    }
+
+    void
+    TreeTypedJSONConverter::visitTime(DataInput& elementData, TypeInput& /*elementType*/)
+    {
+        const std::string key = elementData->getPath().getLastElement();
+        int64_t l = *aron::data::Long::DynamicCastAndCheck(elementData);
+        armem::Time time = armem::Time::microSeconds(l);
+        insertIntoJSON(key, l);
+        if (!jsonStack.top().second.is_array())
+        {
+            insertIntoJSON(key + "_hr", armem::toDateTimeMilliSeconds(time));
+        }
+    }
+
+    template <typename ElementType>
+    void
+    TreeTypedJSONConverter::insertIntoJSON(const std::string& key, const ElementType& data)
+    {
+        if (jsonStack.top().second.is_object())
+        {
+            jsonStack.top().second[key] = nlohmann::json(data);
+        }
+        else
+        {
+            jsonStack.top().second.emplace_back(data);
+        }
+    }
+
+    nlohmann::json
+    TreeTypedJSONConverter::handleGenericNDArray(const aron::data::NDArray& nd)
+    {
+        nlohmann::json ndobj;
+        std::vector<int> shape = nd.getShape();
+        ndobj["dimensions"] = shape;
+        ndobj["type"] = nd.getType();
+
+        int elements =
+            shape.empty()
+                ? 0
+                : std::accumulate(std::begin(shape), std::end(shape), 1, std::multiplies<>());
+        std::vector<unsigned char> d = std::vector<unsigned char>(elements);
+        memcpy(d.data(), nd.getData(), elements);
+        ndobj["data"] = d;
+        return ndobj;
+    }
+} // namespace armarx::armem::gui::instance
diff --git a/source/RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedJSONConverter.h b/source/RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedJSONConverter.h
new file mode 100644
index 0000000000000000000000000000000000000000..7a112979e7baa9e01460cc98d00c3d74a0d846e5
--- /dev/null
+++ b/source/RobotAPI/libraries/armem_gui/instance/tree_visitors/TreeTypedJSONConverter.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <stack>
+#include <utility>
+
+#include <SimoxUtility/json/json.hpp>
+
+#include <RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h>
+
+namespace armarx::armem::gui::instance
+{
+    class TreeTypedJSONConverter : public aron::data::RecursiveConstTypedVariantVisitor
+    {
+    public:
+        TreeTypedJSONConverter();
+        ~TreeTypedJSONConverter() override = default;
+
+        const nlohmann::json& getJSON();
+
+        void visitObjectOnEnter(DataInput& elementData, TypeInput& elementType) override;
+        void visitObjectOnExit(DataInput& elementData, TypeInput& elementType) override;
+        void visitDictOnEnter(DataInput& elementData, TypeInput& elementType) override;
+        void visitDictOnExit(DataInput& elementData, TypeInput& elementType) override;
+        void visitPairOnEnter(DataInput& elementData, TypeInput& elementType) override;
+        void visitPairOnExit(DataInput& elementData, TypeInput& elementType) override;
+        void visitTupleOnEnter(DataInput& elementData, TypeInput& elementType) override;
+        void visitTupleOnExit(DataInput& elementData, TypeInput& elementType) override;
+        void visitListOnEnter(DataInput& elementData, TypeInput& elementType) override;
+        void visitListOnExit(DataInput& elementData, TypeInput& elementType) override;
+
+        void visitMatrix(DataInput& elementData, TypeInput& elementType) override;
+        void visitNDArray(DataInput& elementData, TypeInput& elementType) override;
+        void visitQuaternion(DataInput& elementData, TypeInput& elementType) override;
+        void visitOrientation(DataInput& elementData, TypeInput& elementType) override;
+        void visitPosition(DataInput& elementData, TypeInput& elementType) override;
+        void visitPose(DataInput& elementData, TypeInput& elementType) override;
+        void visitImage(DataInput& elementData, TypeInput& elementType) override;
+        void visitPointCloud(DataInput& elementData, TypeInput& elementType) override;
+        void visitIntEnum(DataInput& elementData, TypeInput& elementType) override;
+        void visitInt(DataInput& elementData, TypeInput& elementType) override;
+        void visitLong(DataInput& elementData, TypeInput& elementType) override;
+        void visitFloat(DataInput& elementData, TypeInput& elementType) override;
+        void visitDouble(DataInput& elementData, TypeInput& elementType) override;
+        void visitBool(DataInput& elementData, TypeInput& elementType) override;
+        void visitString(DataInput& elementData, TypeInput& elementType) override;
+        void visitTime(DataInput& elementData, TypeInput& elementType) override;
+
+    private:
+        std::stack<std::pair<std::string, nlohmann::json>> jsonStack;
+
+        template <typename ElementType>
+        void insertIntoJSON(const std::string& key, const ElementType& data);
+
+        static nlohmann::json handleGenericNDArray(const aron::data::NDArray& nd);
+    };
+} // namespace armarx::armem::gui::instance
diff --git a/source/RobotAPI/libraries/aron/core/data/visitor/RecursiveVisitor.h b/source/RobotAPI/libraries/aron/core/data/visitor/RecursiveVisitor.h
index 2cb8658dba91ffb333f91d62ef318af7e5387955..13bb05bab2971bb2f0fae684c30b26e987b533f5 100644
--- a/source/RobotAPI/libraries/aron/core/data/visitor/RecursiveVisitor.h
+++ b/source/RobotAPI/libraries/aron/core/data/visitor/RecursiveVisitor.h
@@ -128,9 +128,9 @@ namespace armarx::aron::data
             case type::Descriptor::eDict:
             {
                     v.visitDictOnEnter(o, t);
-                    for (auto& [key, value, acceptedType] : v.getDictElements(o, t))
+                    for (auto& [key, pair] : v.getDictElements(o, t))
                     {
-                        visitRecursive(v, value, acceptedType);
+                        visitRecursive(v, pair.first, pair.second);
                     }
                     v.visitDictOnExit(o, t);
                     return;
@@ -138,9 +138,9 @@ namespace armarx::aron::data
             case type::Descriptor::eObject:
             {
                 v.visitObjectOnEnter(o, t);
-                for (auto& [key, value, acceptedType] : v.getObjectElements(o, t))
+                for (auto& [key, pair] : v.getObjectElements(o, t))
                 {
-                    visitRecursive(v, value, acceptedType);
+                    visitRecursive(v, pair.first, pair.second);
                 }
                 v.visitObjectOnExit(o, t);
                 return;