diff --git a/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp b/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp
index cd7e8b18230e38d21cf700f04c116cca830eaa14..d55a0407db9488bae4ca80cc401dcf8cc540f0b7 100644
--- a/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp
+++ b/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.cpp
@@ -27,9 +27,9 @@
 
 #include <SimoxUtility/algorithm/string.h>
 
-#include <RobotAPI/libraries/armem/client/Prediction.h>
 #include <RobotAPI/libraries/armem/client/query/Builder.h>
 #include <RobotAPI/libraries/armem/core/error.h>
+#include <RobotAPI/libraries/armem/core/Prediction.h>
 #include <RobotAPI/libraries/armem/core/ice_conversions.h>
 #include <RobotAPI/libraries/armem/server/MemoryRemoteGui.h>
 
@@ -72,6 +72,9 @@ namespace armarx
         workingMemory().addCoreSegment("ExampleData", armem::example::ExampleData::ToAronType());
         workingMemory().addCoreSegment("LinkedData", armem::example::LinkedData::ToAronType());
 
+        // We support the "Latest" prediction engine for the entire memory.
+        workingMemory().addPredictionEngine({"Latest"});
+
         // For illustration purposes, we add more segments (without types).
         bool trim = true;
         p.core.defaultCoreSegments = simox::alg::split(p.core._defaultSegmentsStr, ",", trim);
@@ -228,7 +231,7 @@ namespace armarx
     armem::prediction::data::PredictionResult
     ExampleMemory::predictSingle(const armem::prediction::data::PredictionRequest& request)
     {
-        armem::client::PredictionResult result;
+        armem::PredictionResult result;
 
         std::string engine = request.settings.predictionEngineID;
         if (engine.empty() || engine == "Latest")
@@ -275,12 +278,6 @@ namespace armarx
         return result.toIce();
     }
 
-    armem::prediction::data::EngineSupportMap
-    ExampleMemory::getAvailableEngines()
-    {
-        return {{armarx::toIce<armem::data::MemoryID>(workingMemory().id()), {{"Latest"}}}};
-    }
-
     // REMOTE GUI
 
     void ExampleMemory::createRemoteGuiTab()
diff --git a/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.h b/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.h
index fa9c2b1eacc314bcb37de05f4f19039d9bcbd582..76e437bcb6f6db0e31c023eed4386831267c5fc2 100644
--- a/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.h
+++ b/source/RobotAPI/components/armem/server/ExampleMemory/ExampleMemory.h
@@ -76,8 +76,6 @@ namespace armarx
         armem::prediction::data::PredictionResultSeq
         predict(const armem::prediction::data::PredictionRequestSeq& requests) override;
 
-        armem::prediction::data::EngineSupportMap getAvailableEngines() override;
-
 
     protected:
 
diff --git a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp
index 02ac6e6aec08d86253f0512584a9921f8063bf9e..fe2a7471594c303e21ed0638bb1fa6f5e1635fa5 100644
--- a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp
+++ b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.cpp
@@ -27,8 +27,8 @@
 
 #include <RobotAPI/libraries/ArmarXObjects/aron_conversions.h>
 #include <RobotAPI/libraries/ArmarXObjects/ice_conversions.h>
-#include <RobotAPI/libraries/armem/client/Prediction.h>
 #include <RobotAPI/libraries/armem/client/query.h>
+#include <RobotAPI/libraries/armem/core/Prediction.h>
 #include <RobotAPI/libraries/armem_objects/aron/ObjectInstance.aron.generated.h>
 
 
@@ -231,8 +231,8 @@ namespace armarx::armem::server::obj
         std::vector<armem::prediction::data::PredictionResult> results;
         for (const auto& request : requests)
         {
-            auto boRequest = armarx::fromIce<armem::client::PredictionRequest>(request);
-            armem::client::PredictionResult result;
+            auto boRequest = armarx::fromIce<armem::PredictionRequest>(request);
+            armem::PredictionResult result;
             result.snapshotID = boRequest.snapshotID;
             if (armem::contains(workingMemory().id().withCoreSegmentName("Instance"),
                                 boRequest.snapshotID) &&
@@ -295,14 +295,6 @@ namespace armarx::armem::server::obj
         return results;
     }
 
-    armem::prediction::data::EngineSupportMap ObjectMemory::getAvailableEngines()
-    {
-        // TODO(phesch): Replace with generic code in Memory implementation
-        return {{armarx::toIce<armem::data::MemoryID>(
-                     workingMemory().id().withCoreSegmentName("Instance")),
-                 {{"Linear Position Regression"}}}};
-    }
-
     void ObjectMemory::createRemoteGuiTab()
     {
         using namespace armarx::RemoteGui::Client;
diff --git a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h
index 7067f42da1344fb4aa1936dfcafaa2b77f3df599..1a939eebff7c94f887b4d68f5d363c5f986e5194 100644
--- a/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h
+++ b/source/RobotAPI/components/armem/server/ObjectMemory/ObjectMemory.h
@@ -110,7 +110,6 @@ namespace armarx::armem::server::obj
         // Predictions
         armem::prediction::data::PredictionResultSeq
         predict(const armem::prediction::data::PredictionRequestSeq& requests) override;
-        armem::prediction::data::EngineSupportMap getAvailableEngines() override;
 
         // Remote GUI
         void createRemoteGuiTab();
diff --git a/source/RobotAPI/interface/armem/server/PredictingMemoryInterface.ice b/source/RobotAPI/interface/armem/server/PredictingMemoryInterface.ice
index ead5ad03b5edd7f1bbb39dd1c528376005c8b041..aeae3745854d595ba7799a399df43cf2e33922b7 100644
--- a/source/RobotAPI/interface/armem/server/PredictingMemoryInterface.ice
+++ b/source/RobotAPI/interface/armem/server/PredictingMemoryInterface.ice
@@ -18,7 +18,7 @@ module armarx
             predict(prediction::data::PredictionRequestSeq requests);
 
             /* Get a map from memory segments to the prediction engines they support.
-             * Best used with the armem::core::PrefixMap to easily retrieve
+             * Best used with the container_map operations to easily retrieve
              * the available engine selection for fully evaluated MemoryIDs.
              */
             prediction::data::EngineSupportMap getAvailableEngines();
diff --git a/source/RobotAPI/libraries/ArmarXObjects/predictions.cpp b/source/RobotAPI/libraries/ArmarXObjects/predictions.cpp
index 427868519c15f4f3c31342f980d3ee245f528a88..fc9dfe5081f69215398cd5c6eefaf7c8c1fbd705 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/predictions.cpp
+++ b/source/RobotAPI/libraries/ArmarXObjects/predictions.cpp
@@ -25,6 +25,7 @@
 #include <SimoxUtility/math/pose/pose.h>
 #include <SimoxUtility/math/regression/linear.h>
 
+#include <ArmarXCore/core/exceptions/local/ExpressionException.h>
 #include <ArmarXCore/core/ice_conversions/ice_conversions_templates.h>
 
 namespace armarx::objpose
diff --git a/source/RobotAPI/libraries/ArmarXObjects/predictions.h b/source/RobotAPI/libraries/ArmarXObjects/predictions.h
index d9b647f9dd81a1e04ff435a0e20c94368cdb89f4..03b3f7de2eb2267ba43c356c44988e374792c591 100644
--- a/source/RobotAPI/libraries/ArmarXObjects/predictions.h
+++ b/source/RobotAPI/libraries/ArmarXObjects/predictions.h
@@ -25,7 +25,6 @@
 
 #include <RobotAPI/interface/objectpose/ObjectPoseStorageInterface.h>
 #include <RobotAPI/libraries/ArmarXObjects/ObjectPose.h>
-#include <RobotAPI/libraries/armem/client/Prediction.h>
 
 namespace armarx::objpose
 {
diff --git a/source/RobotAPI/libraries/armem/CMakeLists.txt b/source/RobotAPI/libraries/armem/CMakeLists.txt
index 237d90fa5c71d2ad987102a443c6438691079e9f..62da8840409c17d8968c34171120a230a379ef33 100644
--- a/source/RobotAPI/libraries/armem/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem/CMakeLists.txt
@@ -18,6 +18,7 @@ set(LIB_FILES
     core/MemoryID.cpp
     core/MemoryID_operators.cpp
     core/operations.cpp
+    core/Prediction.cpp
     core/SuccessHeader.cpp
     core/Time.cpp
     core/aron_conversions.cpp
@@ -51,7 +52,6 @@ set(LIB_FILES
 
 
     client/MemoryNameSystem.cpp
-    client/Prediction.cpp
     client/Reader.cpp
     client/Writer.cpp
 
@@ -82,10 +82,12 @@ set(LIB_HEADERS
 
     core/actions.h
     core/Commit.h
+    core/container_maps.h
     core/DataMode.h
     core/MemoryID.h
     core/MemoryID_operators.h
     core/operations.h
+    core/Prediction.h
     core/SuccessHeader.h
     core/Time.h
     core/aron_conversions.h
@@ -105,6 +107,7 @@ set(LIB_HEADERS
     core/base/detail/iteration_mixins.h
     core/base/detail/lookup_mixins.h
     core/base/detail/negative_index_semantics.h
+    core/base/detail/Predictive.h
 
     core/base/CoreSegmentBase.h
     core/base/EntityBase.h
@@ -126,7 +129,6 @@ set(LIB_HEADERS
     client.h
     client/forward_declarations.h
     client/MemoryNameSystem.h
-    client/Prediction.h
     client/Reader.h
     client/Writer.h
 
diff --git a/source/RobotAPI/libraries/armem/client/Reader.cpp b/source/RobotAPI/libraries/armem/client/Reader.cpp
index ce2d0cfcfa41bedc7f6cab56f45e79d959bc68da..9fb03536bbef6047d96baf6203893ad9cc9f78ed 100644
--- a/source/RobotAPI/libraries/armem/client/Reader.cpp
+++ b/source/RobotAPI/libraries/armem/client/Reader.cpp
@@ -479,7 +479,7 @@ namespace armarx::armem::client
         return boResults;
     }
 
-    armem::prediction::data::EngineSupportMap
+    std::map<MemoryID, std::vector<PredictionEngine>>
     Reader::getAvailablePredictionEngines() const
     {
         if (!predictionPrx)
@@ -499,13 +499,9 @@ namespace armarx::armem::client
             // Just leave engines empty in this case.
         }
 
-        //std::vector<PredictionEngine> boEngines;
-        //boEngines.reserve(engines.size());
-        //for (const auto& engine : engines)
-        //{
-        //    boEngines.push_back(armarx::fromIce<PredictionEngine>(engine));
-        //}
+        std::map<MemoryID, std::vector<PredictionEngine>> boMap;
+        armarx::fromIce(engines, boMap);
 
-        return engines;
+        return boMap;
     }
 } // namespace armarx::armem::client
diff --git a/source/RobotAPI/libraries/armem/client/Reader.h b/source/RobotAPI/libraries/armem/client/Reader.h
index 34b3ce320182c7995412dc7e02b04c58fe1a0dfa..7ecb453c845524edce1a217c49db671efbf3c9e7 100644
--- a/source/RobotAPI/libraries/armem/client/Reader.h
+++ b/source/RobotAPI/libraries/armem/client/Reader.h
@@ -9,10 +9,10 @@
 #include <RobotAPI/interface/armem/server/ReadingMemoryInterface.h>
 #include <RobotAPI/interface/armem/server/StoringMemoryInterface.h>
 #include <RobotAPI/libraries/armem/client/MemoryNameSystem.h>
+#include <RobotAPI/libraries/armem/core/Prediction.h>
 #include <RobotAPI/libraries/armem/core/wm/memory_definitions.h>
 
 #include "Query.h"
-#include "Prediction.h"
 
 
 namespace armarx::armem::client
@@ -178,15 +178,14 @@ namespace armarx::armem::client
          */
         std::vector<PredictionResult> predict(const std::vector<PredictionRequest>& requests) const;
 
-        //TODO(phesch): Fix this interface with the proper type
         /**
          * @brief Get the list of prediction engines supported by the memory.
          *
          * The `predictionPrx` must not be null when calling this function.
          *
-         * @return the vector of supported prediction engines
+         * @return a map from memory containers to their supported engines
          */
-        armem::prediction::data::EngineSupportMap getAvailablePredictionEngines() const;
+        std::map<MemoryID, std::vector<PredictionEngine>> getAvailablePredictionEngines() const;
 
         inline operator bool() const
         {
diff --git a/source/RobotAPI/libraries/armem/client/Prediction.cpp b/source/RobotAPI/libraries/armem/core/Prediction.cpp
similarity index 98%
rename from source/RobotAPI/libraries/armem/client/Prediction.cpp
rename to source/RobotAPI/libraries/armem/core/Prediction.cpp
index dce9473bd58d557d3a37a511c7c257c65305bee8..9880d03a2f4e4c28e649e50f08a1f0b93ce52cb2 100644
--- a/source/RobotAPI/libraries/armem/client/Prediction.cpp
+++ b/source/RobotAPI/libraries/armem/core/Prediction.cpp
@@ -26,7 +26,7 @@
 
 #include <RobotAPI/libraries/armem/core/ice_conversions.h>
 
-namespace armarx::armem::client
+namespace armarx::armem
 {
     PredictionEngine
     PredictionEngine::fromIce(const armem::prediction::data::PredictionEngine& ice)
@@ -132,4 +132,4 @@ namespace armarx::armem::client
         result.prediction = aron::data::Dict::FromAronDictDTO(ice.prediction);
     }
 
-} // namespace armarx::armem::client
+} // namespace armarx::armem
diff --git a/source/RobotAPI/libraries/armem/client/Prediction.h b/source/RobotAPI/libraries/armem/core/Prediction.h
similarity index 97%
rename from source/RobotAPI/libraries/armem/client/Prediction.h
rename to source/RobotAPI/libraries/armem/core/Prediction.h
index 0e9ac30d5e6e797dd228ca6f313c6cdbed19bf5b..a8ec9ee52436b5b5d96c5c8013d058f8d6abc6e5 100644
--- a/source/RobotAPI/libraries/armem/client/Prediction.h
+++ b/source/RobotAPI/libraries/armem/core/Prediction.h
@@ -26,7 +26,7 @@
 #include <RobotAPI/libraries/armem/core/MemoryID.h>
 #include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h>
 
-namespace armarx::armem::client
+namespace armarx::armem
 {
 
     struct PredictionEngine
@@ -83,4 +83,4 @@ namespace armarx::armem::client
     void toIce(armem::prediction::data::PredictionResult& ice, const PredictionResult& result);
     void fromIce(const armem::prediction::data::PredictionResult& ice, PredictionResult& result);
 
-} // namespace armarx::armem::client
+} // namespace armarx::armem
diff --git a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h
index 7fe2f81f4eed5ac478ecb974cf0c09e73de874b3..8c1ed546b3d8699ea4eed9225f055323510745d6 100644
--- a/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/CoreSegmentBase.h
@@ -8,6 +8,7 @@
 #include "detail/MemoryContainerBase.h"
 #include "detail/iteration_mixins.h"
 #include "detail/lookup_mixins.h"
+#include "detail/Predictive.h"
 
 #include <ArmarXCore/core/logging/Logging.h>
 
@@ -21,6 +22,7 @@ namespace armarx::armem::base
     class CoreSegmentBase :
         public detail::MemoryContainerBase<std::map<std::string, _ProviderSegmentT>, _Derived>
         , public detail::AronTyped
+        , public detail::PredictiveContainer<_Derived>
         , public detail::ForEachEntityInstanceMixin<_Derived>
         , public detail::ForEachEntitySnapshotMixin<_Derived>
         , public detail::ForEachEntityMixin<_Derived>
@@ -66,17 +68,23 @@ namespace armarx::armem::base
         CoreSegmentBase()
         {
         }
-        explicit CoreSegmentBase(const std::string& name, aron::type::ObjectPtr aronType = nullptr) :
-            CoreSegmentBase(name, MemoryID(), aronType)
+        explicit CoreSegmentBase(const std::string& name,
+                                 aron::type::ObjectPtr aronType = nullptr,
+                                 const std::vector<PredictionEngine>& predictionEngines = {}) :
+            CoreSegmentBase(name, MemoryID(), aronType, predictionEngines)
         {
         }
-        explicit CoreSegmentBase(const std::string& name, const MemoryID& parentID, aron::type::ObjectPtr aronType = nullptr) :
-            CoreSegmentBase(parentID.withCoreSegmentName(name), aronType)
+        explicit CoreSegmentBase(const std::string& name,
+                                 const MemoryID& parentID,
+                                 aron::type::ObjectPtr aronType = nullptr,
+                                 const std::vector<PredictionEngine>& predictionEngines = {}) :
+            CoreSegmentBase(parentID.withCoreSegmentName(name), aronType, predictionEngines)
         {
         }
-        explicit CoreSegmentBase(const MemoryID& id, aron::type::ObjectPtr aronType = nullptr) :
-            Base(id),
-            AronTyped(aronType)
+        explicit CoreSegmentBase(const MemoryID& id,
+                                 aron::type::ObjectPtr aronType = nullptr,
+                                 const std::vector<PredictionEngine>& predictionEngines = {}) :
+            Base(id), AronTyped(aronType), detail::PredictiveContainer<_Derived>(predictionEngines)
         {
         }
 
@@ -276,15 +284,20 @@ namespace armarx::armem::base
         }
 
         /**
-         * @brief Add an empty provider segment with the given name and optional provider segment type.
+         * @brief Add an empty provider segment with the given name,
+         *        optional provider segment type and prediction engines.
          * @param name The segment name.
          * @param providerSegmentType The provider type. If nullptr, the core segment type is used.
+         * @param predictionEngines The prediction engines supported by the provider segment (optional).
          * @return The added provider segment.
          */
-        ProviderSegmentT& addProviderSegment(const std::string& name, aron::type::ObjectPtr providerSegmentType = nullptr)
+        ProviderSegmentT&
+        addProviderSegment(const std::string& name,
+                           aron::type::ObjectPtr providerSegmentType = nullptr,
+                           const std::vector<PredictionEngine>& predictionEngines = {})
         {
             aron::type::ObjectPtr type = providerSegmentType ? providerSegmentType : this->aronType();
-            return this->_derived().addProviderSegment(name, name, type);
+            return this->_derived().addProviderSegment(name, name, type, predictionEngines);
         }
 
         /// Copy and insert a provider segment.
diff --git a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
index 6a9ce75b7d9e62ae182b7da16eba733a210b279a..b6497f8ff421feb16b7f7b07ede1f2d3e57c2266 100644
--- a/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/MemoryBase.h
@@ -7,6 +7,7 @@
 #include "detail/MemoryContainerBase.h"
 #include "detail/iteration_mixins.h"
 #include "detail/lookup_mixins.h"
+#include "detail/Predictive.h"
 
 
 namespace armarx::armem::base
@@ -18,6 +19,7 @@ namespace armarx::armem::base
     template <class _CoreSegmentT, class _Derived>
     class MemoryBase :
         public detail::MemoryContainerBase<std::map<std::string, _CoreSegmentT>, _Derived>
+        , public detail::PredictiveContainer<_Derived>
         , public detail::ForEachEntityInstanceMixin<_Derived>
         , public detail::ForEachEntitySnapshotMixin<_Derived>
         , public detail::ForEachEntityMixin<_Derived>
@@ -67,12 +69,14 @@ namespace armarx::armem::base
         MemoryBase()
         {
         }
-        explicit MemoryBase(const std::string& name) :
-            MemoryBase(MemoryID().withMemoryName(name))
+        explicit MemoryBase(const std::string& name,
+                            const std::vector<PredictionEngine>& predictionEngines = {}) :
+            MemoryBase(MemoryID().withMemoryName(name), predictionEngines)
         {
         }
-        explicit MemoryBase(const MemoryID& id) :
-            Base(id)
+        explicit MemoryBase(const MemoryID& id,
+                            const std::vector<PredictionEngine>& predictionEngines = {}) :
+            Base(id), detail::PredictiveContainer<_Derived>(predictionEngines)
         {
         }
 
@@ -215,15 +219,18 @@ namespace armarx::armem::base
         // MODIFICATION
 
         /**
-         * @brief Add an empty core segment with the given name.
+         * @brief Add an empty core segment with the given name, type and prediction engines.
          * @param name The core segment name.
          * @param coreSegmentType The core segment type (optional).
+         * @param predictionEngines The prediction engines supported by the core segment (optional).
          * @return The added core segment.
          */
-        CoreSegmentT& addCoreSegment(
-            const std::string& name, aron::type::ObjectPtr coreSegmentType = nullptr)
+        CoreSegmentT&
+        addCoreSegment(const std::string& name,
+                       aron::type::ObjectPtr coreSegmentType = nullptr,
+                       const std::vector<PredictionEngine>& predictionEngines = {})
         {
-            return this->_derived().addCoreSegment(name, name, coreSegmentType);
+            return this->_derived().addCoreSegment(name, name, coreSegmentType, predictionEngines);
         }
 
         /// Copy and insert a core segment.
diff --git a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h
index 02f47105d2a8591e8953179edb00fbe81fffbc3e..6cd70391660d6f61fe073837052a9b06fb57da1c 100644
--- a/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h
+++ b/source/RobotAPI/libraries/armem/core/base/ProviderSegmentBase.h
@@ -3,8 +3,11 @@
 #include <map>
 #include <string>
 
+#include <RobotAPI/libraries/armem/core/Prediction.h>
+
 #include "EntityBase.h"
 #include "detail/AronTyped.h"
+#include "detail/Predictive.h"
 #include "detail/MemoryContainerBase.h"
 #include "detail/iteration_mixins.h"
 #include "detail/lookup_mixins.h"
@@ -20,6 +23,7 @@ namespace armarx::armem::base
     class ProviderSegmentBase :
         public detail::MemoryContainerBase<std::map<std::string, _EntityT>, _Derived>
         , public detail::AronTyped
+        , public detail::Predictive<_Derived>
         , public detail::ForEachEntityInstanceMixin<_Derived>
         , public detail::ForEachEntitySnapshotMixin<_Derived>
         , public detail::GetFindInstanceMixin<_Derived>
@@ -60,17 +64,26 @@ namespace armarx::armem::base
         {
         }
 
-        explicit ProviderSegmentBase(const std::string& name, aron::type::ObjectPtr aronType = nullptr) :
-            ProviderSegmentBase(name, MemoryID(), aronType)
+        explicit ProviderSegmentBase(
+            const std::string& name,
+            aron::type::ObjectPtr aronType = nullptr,
+            const std::vector<PredictionEngine>& predictionEngines = {}) :
+            ProviderSegmentBase(name, MemoryID(), aronType, predictionEngines)
         {
         }
-        explicit ProviderSegmentBase(const std::string& name, const MemoryID parentID, aron::type::ObjectPtr aronType = nullptr) :
-            ProviderSegmentBase(parentID.withProviderSegmentName(name), aronType)
+        explicit ProviderSegmentBase(
+            const std::string& name,
+            const MemoryID parentID,
+            aron::type::ObjectPtr aronType = nullptr,
+            const std::vector<PredictionEngine>& predictionEngines = {}) :
+            ProviderSegmentBase(parentID.withProviderSegmentName(name), aronType, predictionEngines)
         {
         }
-        explicit ProviderSegmentBase(const MemoryID id, aron::type::ObjectPtr aronType = nullptr) :
-            Base(id),
-            AronTyped(aronType)
+        explicit ProviderSegmentBase(
+            const MemoryID id,
+            aron::type::ObjectPtr aronType = nullptr,
+            const std::vector<PredictionEngine>& predictionEngines = {}) :
+            Base(id), AronTyped(aronType), detail::Predictive<_Derived>(predictionEngines)
         {
         }
 
diff --git a/source/RobotAPI/libraries/armem/core/base/detail/Predictive.h b/source/RobotAPI/libraries/armem/core/base/detail/Predictive.h
new file mode 100644
index 0000000000000000000000000000000000000000..ea9ec0dde71cbdb19c6bebe0e160bfbcea8c8155
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/core/base/detail/Predictive.h
@@ -0,0 +1,125 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::armem::core::base::detail
+ * @author     phesch ( phesch at student dot kit dot edu )
+ * @date       2022
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <RobotAPI/libraries/armem/core/MemoryID.h>
+#include <RobotAPI/libraries/armem/core/Prediction.h>
+
+#include "derived.h"
+
+
+namespace armarx::armem::base::detail
+{
+
+    /**
+     * @brief Something that supports a set of prediction engines.
+     */
+    template <class DerivedT>
+    class Predictive
+    {
+    public:
+
+        explicit Predictive(const std::vector<PredictionEngine>& engines = {}) :
+            _predictionEngines(engines)
+        {
+        }
+
+        const std::vector<PredictionEngine>&
+        predictionEngines() const
+        {
+            return _predictionEngines;
+        }
+
+        void addPredictionEngine(const PredictionEngine& engine)
+        {
+            _predictionEngines.push_back(engine);
+        }
+
+        void setPredictionEngines(const std::vector<PredictionEngine>& engines)
+        {
+            this->_predictionEngines = engines;
+        }
+
+        std::map<MemoryID, std::vector<PredictionEngine>>
+        getAllPredictionEngines() const
+        {
+            std::map<MemoryID, std::vector<PredictionEngine>> engines;
+
+            // Add own engines.
+            const auto& derivedThis = derived<DerivedT>(this);
+            const auto& ownEngines = derivedThis.predictionEngines();
+            if (not ownEngines.empty())
+            {
+                engines.emplace(derivedThis.id(), derivedThis.predictionEngines());
+            }
+
+            return engines;
+        }
+
+
+    private:
+
+        std::vector<PredictionEngine> _predictionEngines;
+
+    };
+
+
+    /**
+     * @brief Something that supports a set of prediction engines.
+     */
+    template <class DerivedT>
+    class PredictiveContainer : public Predictive<DerivedT>
+    {
+    public:
+
+        using Predictive<DerivedT>::Predictive;
+
+
+        std::map<MemoryID, std::vector<PredictionEngine>>
+        getAllPredictionEngines() const
+        {
+            std::map<MemoryID, std::vector<PredictionEngine>> engines;
+
+            // Collect engines of children.
+            const auto& derivedThis = derived<DerivedT>(this);
+            derivedThis.forEachChild(
+                [&engines](const auto& child)
+                {
+                    const auto& childMap = child.getAllPredictionEngines();
+                    engines.insert(childMap.begin(), childMap.end());
+                });
+
+            // Add own engines.
+            const auto& ownEngines = derivedThis.predictionEngines();
+            if (not ownEngines.empty())
+            {
+                engines.emplace(derivedThis.id(), derivedThis.predictionEngines());
+            }
+
+            return engines;
+        }
+
+    };
+
+
+} // namespace armarx::armem::base::detail
diff --git a/source/RobotAPI/libraries/armem/core/container_maps.h b/source/RobotAPI/libraries/armem/core/container_maps.h
new file mode 100644
index 0000000000000000000000000000000000000000..625c92bb02548c66b96c18e349bbe23acc0385ef
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/core/container_maps.h
@@ -0,0 +1,232 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @author     phesch ( ulila at student dot kit dot edu )
+ * @date       2022
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <map>
+#include <optional>
+#include <tuple>
+
+#include <RobotAPI/libraries/armem/core/MemoryID.h>
+
+namespace armarx::armem
+{
+
+    namespace detail
+    {
+    template <class KeyT, class ValueT>
+    struct MapRef
+    {
+        KeyT* key;
+        ValueT* value;
+    };
+
+
+
+        /**
+        * @brief Get the entry in the map for which the returned key is the longest prefix
+        *        of the given key among the keys in the map.
+        *
+        * `prefixFunc` is used to successively calculate the prefixes of the given key.
+        * It must be pure and return an empty optional when there is no shorter
+        * prefix of the given key (for strings, this would be the case when passed the empty string).
+        *
+        * @param keyValMap the map that contains the key-value-pairs to search
+        * @param prefixFunc the function that returns the longest non-identical prefix of the key
+        * @param key the key to calculate the prefixes of
+        *
+        * @return The iterator pointing to the found entry, or `keyValMap.end()`.
+        */
+        template <typename KeyT, typename ValueT>
+        typename std::map<KeyT, ValueT>::const_iterator
+        findEntryWithLongestPrefix(const std::map<KeyT, ValueT>& keyValMap,
+                                   const std::function<std::optional<KeyT>(KeyT&)>& prefixFunc,
+                                   const KeyT& key)
+        {
+            std::optional<KeyT> curKey = key;
+
+            typename std::map<KeyT, ValueT>::const_iterator result = keyValMap.end();
+            do
+            {
+                auto iterator = keyValMap.find(curKey.value());
+                if (iterator != keyValMap.end())
+                {
+                    result = iterator;
+                }
+                else
+                {
+                    curKey = prefixFunc(curKey.value());
+                }
+            }
+            while (result == keyValMap.end() and curKey.has_value());
+
+            return result;
+        }
+
+
+        /**
+        * @brief Accumulate all the values in a map for which the keys are prefixes of the given key.
+        *
+        * `AccumulateT` is a type that the values will be accumulated into using `accumulateFunc`.
+        * `accumulateFunc` is a function that modifies the given accumulator
+        * (by, e.g., adding the given value to it).
+        *
+        * The values are accumulated in order from the longest key to the shortest. 
+        *
+        * @see `getWithLongestPrefix` for a description of `prefixFunc`
+        * @param keyValMap the map that contains the key-value-pairs to search
+        * @param prefixFunc the function that returns the longest non-identical prefix of the key
+        * @param accumulateFunc the function that accumulates the values in the accumulator
+        * @param key the key to calculate the prefixes of
+        */
+        template <typename KeyT, typename ValueT, typename AccumulateT>
+        AccumulateT
+        accumulateFromPrefixes(const std::map<KeyT, ValueT>& keyValMap,
+                               const std::function<std::optional<KeyT>(const KeyT&)>& prefixFunc,
+                               const std::function<void(AccumulateT&, const ValueT&)> accumulateFunc,
+                               const KeyT& key)
+        {
+            std::optional<KeyT> curKey = key;
+            AccumulateT values;
+            do
+            {
+                const auto nextEntry =
+                    findEntryWithLongestPrefix<KeyT, ValueT>(keyValMap, prefixFunc, curKey.value());
+                if (nextEntry != keyValMap.end())
+                {
+                    curKey = prefixFunc(nextEntry->first);
+                    accumulateFunc(values, nextEntry->second);
+                }
+                else
+                {
+                    curKey.reset();
+                }
+            }
+            while (curKey.has_value());
+
+            return values;
+        }
+
+        /**
+        * @brief Collect all the values in a map for which the keys are prefixes of the given key.
+        *
+        * This is a specialization of the general `accumulateFromPrefixes`
+        * for collecting single values into a vector.
+        *
+        * @see `accumulateFromPrefixes` for a detailed description
+        * @param keyValMap the map that contains the key-value-pairs to search
+        * @param prefixFunc the function that returns the longest non-identical prefix of the key
+        * @param key the key to calculate the prefixes of
+        */
+        template <typename KeyT, typename ValueT>
+        std::vector<ValueT>
+        accumulateFromPrefixes(const std::map<KeyT, ValueT>& keyValMap,
+                               const std::function<std::optional<KeyT>(const KeyT&)>& prefixFunc,
+                               const KeyT& key)
+        {
+            return accumulateFromPrefixes<KeyT, ValueT, std::vector<ValueT>>(
+                keyValMap,
+                prefixFunc,
+                [](std::vector<ValueT>& values, const ValueT& val) { values.push_back(val); },
+                key);
+        }
+
+        /**
+        * @brief Collect all the values in a map for which the keys are prefixes of the given key.
+        *
+        * This is a specialization of the general `accumulateFromPrefixes`
+        * for appending vector values into a single vector.
+        *
+        * @see `accumulateFromPrefixes` for a detailed description
+        * @param keyValMap the map that contains the key-value-pairs to search
+        * @param prefixFunc the function that returns the longest non-identical prefix of the key
+        * @param key the key to calculate the prefixes of
+        */
+        template <typename KeyT, typename ValueT>
+        std::vector<ValueT>
+        accumulateFromPrefixes(const std::map<KeyT, std::vector<ValueT>>& keyValMap,
+                               const std::function<std::optional<KeyT>(const KeyT&)>& prefixFunc,
+                               const KeyT& key)
+        {
+            return accumulateFromPrefixes<KeyT, std::vector<ValueT>, std::vector<ValueT>>(
+                keyValMap,
+                prefixFunc,
+                [](std::vector<ValueT>& values, const std::vector<ValueT>& val)
+                { values.insert(values.end(), val.begin(), val.end()); },
+                key);
+        }
+
+    } // namespace detail
+
+
+    std::optional<MemoryID> inline getMemoryIDParent(const MemoryID& memID)
+    {
+        if (!memID.hasMemoryName())
+        {
+            return std::nullopt;
+        }
+        MemoryID parent = memID.removeLeafItem();
+        return {parent};
+    }
+
+
+    /**
+     * @brief Find the entry with the most specific key that contains the given ID,
+     * or `idMap.end()` if no key contains the ID.
+     *
+     * @see `detail::findEntryWithLongestPrefix()`
+     */
+    template <typename ValueT>
+    typename std::map<MemoryID, ValueT>::const_iterator
+    findMostSpecificEntryContainingID(const std::map<MemoryID, ValueT>& idMap, const MemoryID& id)
+    {
+        return detail::findEntryWithLongestPrefix<MemoryID, ValueT>(idMap, &getMemoryIDParent, id);
+    }
+
+
+    /**
+     * @brief Return all values of keys containing the given ID.
+     *
+     * @see `detail::accumulateFromPrefixes()`
+     */
+    template <typename ValueT>
+    std::vector<ValueT>
+    accumulateEntriesContainingID(const std::map<MemoryID, ValueT>& idMap, const MemoryID& id)
+    {
+        return detail::accumulateFromPrefixes<MemoryID, ValueT>(idMap, &getMemoryIDParent, id);
+    }
+
+
+    /**
+     * @brief Return all values of keys containing the given ID in a flattened vector.
+     *
+     * @see `detail::accumulateFromPrefixes()`
+     */
+    template <typename ValueT>
+    std::vector<ValueT>
+    accumulateEntriesContainingID(const std::map<MemoryID, std::vector<ValueT>>& idMap,
+                                  const MemoryID& key)
+    {
+        return detail::accumulateFromPrefixes<MemoryID, ValueT>(idMap, &getMemoryIDParent, key);
+    }
+
+
+} // namespace armarx::armem
diff --git a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp
index 1400107eaa926207ce2cc7b1a07f508897038c88..a10a398186c73734a841dbf3e40cf8db11987769 100644
--- a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp
+++ b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.cpp
@@ -359,4 +359,32 @@ namespace armarx::armem::server
         return output;
     }
 
+    // PREDICTION
+    prediction::data::EngineSupportMap MemoryToIceAdapter::getAvailableEngines()
+    {
+        prediction::data::EngineSupportMap result;
+        armarx::toIce(result, workingMemory->getAllPredictionEngines());
+
+        prediction::data::EngineSupportMap ltmMap;
+        armarx::toIce(ltmMap, workingMemory->getAllPredictionEngines());
+        for (const auto& [memoryID, engines] : ltmMap)
+        {
+            auto entryIter = result.find(memoryID);
+            if (entryIter == result.end())
+            {
+                result.emplace(memoryID, engines);
+            }
+            else
+            {
+                // Merge LTM-supported engines with WM-supported engines, removing duplicates
+                std::set<prediction::data::PredictionEngine> engineSet;
+                engineSet.insert(entryIter->second.begin(), entryIter->second.end());
+                engineSet.insert(engines.begin(), engines.end());
+                entryIter->second.assign(engineSet.begin(), engineSet.end());
+            }
+        }
+
+        return result;
+    }
+
 }
diff --git a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h
index 33e788ff566ca4f06b369160112f54160b425b46..96c1e822d6f4150c6e341bd5c0d234f57efec2b5 100644
--- a/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h
+++ b/source/RobotAPI/libraries/armem/server/MemoryToIceAdapter.h
@@ -52,6 +52,9 @@ namespace armarx::armem::server
         // LTM STORING
         data::StoreResult store(const armem::data::StoreInput& input);
 
+        // PREDICTION
+        prediction::data::EngineSupportMap getAvailableEngines();
+
     public:
 
         server::wm::Memory* workingMemory;
diff --git a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp
index f690cbaeef48944c8568ef58b0aae08b82735513..44454b87d83b905edff8b925b0aa5831ffd8715e 100644
--- a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp
+++ b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.cpp
@@ -1,8 +1,8 @@
 #include "ReadWritePluginUser.h"
 #include "Plugin.h"
 
-#include <RobotAPI/libraries/armem/client/Prediction.h>
 #include <RobotAPI/libraries/armem/core/error.h>
+#include <RobotAPI/libraries/armem/core/Prediction.h>
 #include <RobotAPI/libraries/armem/server/MemoryToIceAdapter.h>
 
 #include <ArmarXCore/core/Component.h>
@@ -125,7 +125,7 @@ namespace armarx::armem::server::plugins
         armem::prediction::data::PredictionResultSeq result;
         for (auto request : requests)
         {
-            armem::client::PredictionResult singleResult;
+            armem::PredictionResult singleResult;
             singleResult.success = false;
             singleResult.errorMessage = "This memory does not implement predictions.";
             singleResult.prediction = nullptr;
@@ -137,7 +137,7 @@ namespace armarx::armem::server::plugins
     armem::prediction::data::EngineSupportMap
     ReadWritePluginUser::getAvailableEngines()
     {
-        return {};
+        return iceAdapter().getAvailableEngines();
     }
 
     armem::prediction::data::PredictionResultSeq
diff --git a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h
index 37f25fd8f3199179402755dc76d98367964aa2af..8ddf174b172d4eb2fc4fba7f3e89d79553d72b42 100644
--- a/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h
+++ b/source/RobotAPI/libraries/armem/server/plugins/ReadWritePluginUser.h
@@ -57,6 +57,10 @@ namespace armarx::armem::server::plugins
 
         // PredictingInterface interface
         virtual armem::prediction::data::PredictionResultSeq predict(const armem::prediction::data::PredictionRequestSeq& requests);
+
+        // Unless you need very unusual behavior from this method for your memory server,
+        // it is better to set the available prediction engines in the memory itself
+        // and let it handle the requests than to override this.
         virtual armem::prediction::data::EngineSupportMap getAvailableEngines();
 
         virtual armem::prediction::data::PredictionResultSeq predict(const armem::prediction::data::PredictionRequestSeq& requests, const ::Ice::Current&) override;
diff --git a/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.cpp b/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.cpp
index b0afa282677c45325993feee0fcba60245236611..818c2d38520fa55b31390cff00123720f0fdbefd 100644
--- a/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.cpp
+++ b/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.cpp
@@ -14,9 +14,11 @@ namespace armarx::armem::server::segment
             armem::server::MemoryToIceAdapter& iceMemory,
             const std::string& defaultCoreSegmentName,
             aron::type::ObjectPtr coreSegmentAronType,
-            int defaultMaxHistorySize) :
+            int defaultMaxHistorySize,
+            const std::vector<PredictionEngine>& predictionEngines) :
         Base(iceMemory),
         aronType(coreSegmentAronType),
+        predictionEngines(predictionEngines),
         properties({defaultCoreSegmentName, defaultMaxHistorySize})
     {
         Logging::setTag("armarx::armem::SpecializedCoreSegment");
@@ -60,6 +62,7 @@ namespace armarx::armem::server::segment
 
             segmentPtr->aronType() = aronType;
             segmentPtr->setMaxHistorySize(properties.maxHistorySize);
+            segmentPtr->setPredictionEngines(predictionEngines);
         }
     }
 
@@ -80,6 +83,13 @@ namespace armarx::armem::server::segment
         this->aronType = aronType;
     }
 
+    void
+    SpecializedCoreSegment::setPredictionEngines(
+        const std::vector<PredictionEngine>& predictionEngines)
+    {
+        this->predictionEngines = predictionEngines;
+    }
+
     wm::CoreSegment& SpecializedCoreSegment::getCoreSegment()
     {
         ARMARX_CHECK_NOT_NULL(segmentPtr);
diff --git a/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.h b/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.h
index d94fa1aed5632e752fec44bbfeadc91b1c7e34bd..5ddca3e7d1dc0820a29039dba17af1e956d9897c 100644
--- a/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.h
+++ b/source/RobotAPI/libraries/armem/server/segment/SpecializedCoreSegment.h
@@ -27,7 +27,8 @@ namespace armarx::armem::server::segment
                 MemoryToIceAdapter& iceMemory,
                 const std::string& defaultCoreSegmentName = "",
                 aron::type::ObjectPtr coreSegmentAronType = nullptr,
-                int defaultMaxHistorySize = -1);
+                int defaultMaxHistorySize = -1,
+                const std::vector<PredictionEngine>& predictionEngines = {});
 
             virtual ~SpecializedCoreSegment() override;
 
@@ -43,6 +44,8 @@ namespace armarx::armem::server::segment
             void setDefaultCoreSegmentName(const std::string& coreSegmentName);
             void setDefaultMaxHistorySize(int64_t maxHistorySize);
             void setAronType(aron::type::ObjectPtr aronType);
+            void
+            setPredictionEngines(const std::vector<PredictionEngine>& predictionEngines);
 
             wm::CoreSegment& getCoreSegment();
             const wm::CoreSegment& getCoreSegment() const;
@@ -51,6 +54,7 @@ namespace armarx::armem::server::segment
         public:
 
             aron::type::ObjectPtr aronType;
+            std::vector<PredictionEngine> predictionEngines;
 
             struct Properties
             {
diff --git a/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.cpp b/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.cpp
index 747b2bec833e5f1b13366e2954b5af4f12f64b4b..f5ab3b86543d601310a02a0de59820a2d459a32e 100644
--- a/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.cpp
+++ b/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.cpp
@@ -10,15 +10,22 @@
 namespace armarx::armem::server::segment
 {
     SpecializedProviderSegment::SpecializedProviderSegment(
-            armem::server::MemoryToIceAdapter& iceMemory,
-            const std::string& defaultProviderSegmentName,
-            const std::string& defaultCoreSegmentName,
-            aron::type::ObjectPtr providerSegmentAronType,
-            aron::type::ObjectPtr coreSegmentAronType,
-            int defaultMaxHistorySize) :
+        armem::server::MemoryToIceAdapter& iceMemory,
+        const std::string& defaultProviderSegmentName,
+        const std::string& defaultCoreSegmentName,
+        aron::type::ObjectPtr providerSegmentAronType,
+        aron::type::ObjectPtr coreSegmentAronType,
+        int defaultMaxHistorySize,
+        const std::vector<PredictionEngine>& providerSegmentPredictionEngines,
+        const std::vector<PredictionEngine>& coreSegmentPredictionEngines) :
         Base(iceMemory),
         aronType(providerSegmentAronType),
-        coreSegment(iceMemory, defaultCoreSegmentName, coreSegmentAronType),
+        predictionEngines(providerSegmentPredictionEngines),
+        coreSegment(iceMemory,
+                    defaultCoreSegmentName,
+                    coreSegmentAronType,
+                    -1,
+                    providerSegmentPredictionEngines),
         properties({defaultProviderSegmentName, defaultMaxHistorySize})
     {
         Logging::setTag("armarx::armem::SpecializedProviderSegment");
@@ -65,6 +72,7 @@ namespace armarx::armem::server::segment
 
             segmentPtr->aronType() = aronType;
             segmentPtr->setMaxHistorySize(properties.maxHistorySize);
+            segmentPtr->setPredictionEngines(predictionEngines);
         }
     }
 
@@ -85,6 +93,13 @@ namespace armarx::armem::server::segment
         this->aronType = aronType;
     }
 
+    void
+    SpecializedProviderSegment::setPredictionEngines(
+        const std::vector<PredictionEngine>& predictionEngines)
+    {
+        this->predictionEngines = predictionEngines;
+    }
+
     wm::ProviderSegment& SpecializedProviderSegment::getProviderSegment()
     {
         ARMARX_CHECK_NOT_NULL(segmentPtr);
diff --git a/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.h b/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.h
index 44db000d18e7804c99e1cc1d412cd3efe5b9b652..3cb50c52f42ba2e2ca35a5024755729b9226336f 100644
--- a/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.h
+++ b/source/RobotAPI/libraries/armem/server/segment/SpecializedProviderSegment.h
@@ -29,7 +29,9 @@ namespace armarx::armem::server::segment
                 const std::string& defaultCoreSegmentName = "",
                 aron::type::ObjectPtr providerSegmentAronType = nullptr,
                 aron::type::ObjectPtr coreSegmentAronType = nullptr,
-                int defaultMaxHistorySize = -1);
+                int defaultMaxHistorySize = -1,
+                const std::vector<PredictionEngine>& providerSegmentPredictionEngines = {},
+                const std::vector<PredictionEngine>& coreSegmentPredictionEngines = {});
 
             virtual ~SpecializedProviderSegment() override;
 
@@ -39,6 +41,8 @@ namespace armarx::armem::server::segment
             void setDefaultProviderSegmentName(const std::string& providerSegmentName);
             void setDefaultMaxHistorySize(int64_t maxHistorySize);
             void setAronType(aron::type::ObjectPtr aronType);
+            void
+            setPredictionEngines(const std::vector<PredictionEngine>& predictionEngines);
 
             wm::ProviderSegment& getProviderSegment();
             const wm::ProviderSegment& getProviderSegment() const;
@@ -47,6 +51,7 @@ namespace armarx::armem::server::segment
         public:
 
             aron::type::ObjectPtr aronType;
+            std::vector<PredictionEngine> predictionEngines;
             SpecializedCoreSegment coreSegment;
 
             struct Properties
diff --git a/source/RobotAPI/libraries/armem/test/ArMemPrefixesTest.cpp b/source/RobotAPI/libraries/armem/test/ArMemPrefixesTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4efc404325b61dbea0f68c7ec1bda5ecb051b8c6
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/test/ArMemPrefixesTest.cpp
@@ -0,0 +1,94 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::armem
+ * @author     phesch ( ulila at student dot kit dot edu )
+ * @date       2022
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#define BOOST_TEST_MODULE RobotAPI::armem
+
+#define ARMARX_BOOST_TEST
+
+#include <iostream>
+
+#include <RobotAPI/Test.h>
+#include <RobotAPI/libraries/armem/core/error.h>
+#include <RobotAPI/libraries/armem/core/container_maps.h>
+
+
+namespace armem = armarx::armem;
+
+BOOST_AUTO_TEST_CASE(test_MemoryID_prefixes)
+{
+    std::map<armem::MemoryID, int> idMap;
+    std::map<armem::MemoryID, std::vector<int>> idListMap;
+    armem::MemoryID empty;
+    armem::MemoryID complete("mem", "coreSeg", "provSeg", "entity", armarx::DateTime::Now(), 0);
+
+    BOOST_TEST_CONTEXT(VAROUT(idMap))
+    {
+        BOOST_CHECK(armem::findMostSpecificEntryContainingID(idMap, empty) == idMap.end());
+        BOOST_CHECK(armem::findMostSpecificEntryContainingID(idMap, complete) == idMap.end());
+        BOOST_CHECK(armem::accumulateEntriesContainingID(idMap, empty).empty());
+        BOOST_CHECK(armem::accumulateEntriesContainingID(idMap, complete).empty());
+
+        BOOST_CHECK(armem::accumulateEntriesContainingID(idListMap, empty).empty());
+        BOOST_CHECK(armem::accumulateEntriesContainingID(idListMap, complete).empty());
+    }
+
+    idMap[armem::MemoryID()] = 0;
+    idMap.emplace("mem", 1);
+    idMap.emplace("mem/coreSeg", 2);
+    idMap.emplace("mem/coreSeg/provSeg", 3);
+    idMap.emplace("mem/otherSeg/provSeg", 10);
+
+    BOOST_TEST_CONTEXT(VAROUT(idMap))
+    {
+        auto it = armem::findMostSpecificEntryContainingID(idMap, empty);
+        BOOST_CHECK(it != idMap.end());
+        BOOST_CHECK_EQUAL(it->second, 0);
+
+        it = armem::findMostSpecificEntryContainingID(idMap, complete.getCoreSegmentID());
+        BOOST_CHECK(it != idMap.end());
+        BOOST_CHECK_EQUAL(it->second, 2);
+
+        it = armem::findMostSpecificEntryContainingID(idMap, complete);
+        BOOST_CHECK(it != idMap.end());
+        BOOST_CHECK_EQUAL(it->second, 3);
+
+        BOOST_CHECK((armem::accumulateEntriesContainingID(idMap, empty) == std::vector<int>{0}));
+        BOOST_CHECK((armem::accumulateEntriesContainingID(idMap, complete.getCoreSegmentID()) ==
+                     std::vector<int>{2, 1, 0}));
+        BOOST_CHECK(
+            (armem::accumulateEntriesContainingID(idMap, complete) == std::vector<int>{3, 2, 1, 0}));
+    }
+
+    idListMap.emplace("mem", std::vector<int>{1, 2});
+    idListMap.emplace("mem/coreSeg", std::vector<int>{3, 4, 5});
+    idListMap.emplace("mem/coreSeg/provSeg", std::vector<int>{6, 7, 8});
+    idListMap.emplace("mem/otherSeg/provSeg", std::vector<int>{9, 10, 11});
+
+    BOOST_TEST_CONTEXT(VAROUT(idListMap))
+    {
+        BOOST_CHECK((armem::accumulateEntriesContainingID(idListMap, empty).empty()));
+        BOOST_CHECK((armem::accumulateEntriesContainingID(idListMap, complete.getCoreSegmentID()) ==
+                     std::vector<int>{3, 4, 5, 1, 2}));
+        BOOST_CHECK((armem::accumulateEntriesContainingID(idListMap, complete) ==
+                     std::vector<int>{6, 7, 8, 3, 4, 5, 1, 2}));
+    }
+}
diff --git a/source/RobotAPI/libraries/armem/test/CMakeLists.txt b/source/RobotAPI/libraries/armem/test/CMakeLists.txt
index 592b9aef3105bd7fc780c92348cae11e60f65a6d..da77a43b82a6174b756ddf1705e8c29ea3acabb2 100644
--- a/source/RobotAPI/libraries/armem/test/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem/test/CMakeLists.txt
@@ -7,3 +7,4 @@ armarx_add_test(ArMemGetFindTest ArMemGetFindTest.cpp "${LIBS}")
 armarx_add_test(ArMemIceConversionsTest ArMemIceConversionsTest.cpp "${LIBS}")
 armarx_add_test(ArMemMemoryIDTest ArMemMemoryIDTest.cpp "${LIBS}")
 armarx_add_test(ArMemQueryBuilderTest ArMemQueryBuilderTest.cpp "${LIBS}")
+armarx_add_test(ArMemPrefixesTest ArMemPrefixesTest.cpp "${LIBS}")
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
index 6bad86c0f05ccdaa33855d9411c27d9cc04d50f6..aaf23c20e21eff50cf135664b6c8c951d9980abd 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.cpp
@@ -49,8 +49,11 @@ namespace armarx::armem::server::obj::instance
 {
 
     Segment::Segment(armem::server::MemoryToIceAdapter& memoryToIceAdapter) :
-        SpecializedCoreSegment(memoryToIceAdapter, "Instance",
-                           arondto::ObjectInstance::ToAronType(), 64)
+        SpecializedCoreSegment(memoryToIceAdapter,
+                               "Instance",
+                               arondto::ObjectInstance::ToAronType(),
+                               64,
+                               predictionEngines)
     {
         oobbCache.setFetchFn([this](const ObjectID & id) -> std::optional<simox::OrientedBoxf>
         {
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h
index 0aa9b930411f0a6f6336ea439fbb98ff6dc74a50..ba7c5539df7299be11ceead0c4253938bfe9ed73 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/Segment.h
@@ -18,7 +18,7 @@
 #include <RobotAPI/libraries/ArmarXObjects/ObjectFinder.h>
 #include <RobotAPI/libraries/ArmarXObjects/forward_declarations.h>
 
-#include <RobotAPI/libraries/armem/client/Prediction.h>
+#include <RobotAPI/libraries/armem/core/Prediction.h>
 #include <RobotAPI/libraries/armem/server/wm/memory_definitions.h>
 #include <RobotAPI/libraries/armem/server/segment/SpecializedSegment.h>
 
@@ -194,7 +194,6 @@ namespace armarx::armem::server::obj::instance
 
         static const std::string timestampPlaceholder;
 
-
     public:
 
         struct RemoteGui
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp
index 7c7dac41c1a74bca1606721b86de565f821a7608..7a36b0cbce48d258eded0545492bd4974019069f 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.cpp
@@ -68,6 +68,7 @@ namespace armarx::armem::server::obj::instance
     {
         segment.setTag(getName());
         segment.decay.setTag(getName());
+        segment.setPredictionEngines(predictionEngines);
         robotHead.setTag(getName());
         visu.setTag(getName());
 
@@ -494,11 +495,11 @@ namespace armarx::armem::server::obj::instance
 
             if (result.success)
             {
-                armem::client::PredictionSettings settings =
-                        armem::client::PredictionSettings::fromIce(request.settings);
+                armem::PredictionSettings settings =
+                        armem::PredictionSettings::fromIce(request.settings);
 
                 if (settings.predictionEngineID.empty()
-                    or settings.predictionEngineID == "Linear Position Regression")
+                    or settings.predictionEngineID == linearPredictionEngineID)
                 {
                     result = objpose::predictObjectPoseLinear(
                         poses.at(i),
@@ -519,10 +520,7 @@ namespace armarx::armem::server::obj::instance
     armem::prediction::data::PredictionEngineSeq
     SegmentAdapter::getAvailableObjectPoseEngines(const Ice::Current&)
     {
-        armem::prediction::data::PredictionEngine engine;
-        // TODO(phesch): Make this a constant somewhere
-        engine.engineID = "Linear Position Regression";
-        return { engine };
+        return armarx::toIce<armem::prediction::data::PredictionEngineSeq>(predictionEngines);
     }
 
     void
@@ -600,6 +598,10 @@ namespace armarx::armem::server::obj::instance
             cycle.waitForCycleDuration();
         }
     }
+    
+
+    const std::string SegmentAdapter::linearPredictionEngineID = "Linear Position Regression";
+    const std::vector<PredictionEngine> SegmentAdapter::predictionEngines{{linearPredictionEngineID}};
 
 
     void SegmentAdapter::Calibration::defineProperties(PropertyDefinitionsPtr defs, const std::string& prefix)
@@ -609,7 +611,6 @@ namespace armarx::armem::server::obj::instance
     }
 
 
-
     void SegmentAdapter::RemoteGui::setup(const SegmentAdapter& adapter)
     {
         using namespace armarx::RemoteGui::Client;
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.h b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.h
index 69595f7b640ec57cb1dcd7222233e7681f6f20e1..aafe61f5c87e5a1363ef837d56cd7cbeec08407c 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.h
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/SegmentAdapter.h
@@ -116,7 +116,9 @@ namespace armarx::armem::server::obj::instance
         virtual armem::prediction::data::PredictionEngineSeq
             getAvailableObjectPoseEngines(ICE_CURRENT_ARG) override;
 
+
     private:
+
         void updateProviderInfo(const std::string& providerName, const objpose::ProviderInfo& info);
 
         void updateObjectPoses(const std::string& providerName, const objpose::data::ProvidedObjectPoseSeq& providedPoses);
@@ -128,6 +130,12 @@ namespace armarx::armem::server::obj::instance
         void visualizeRun();
 
 
+    public:
+
+        static const std::string linearPredictionEngineID;
+        static const std::vector<PredictionEngine> predictionEngines;
+
+
     private:
 
         viz::Client arviz;
diff --git a/source/RobotAPI/libraries/armem_objects/server/instance/Visu.cpp b/source/RobotAPI/libraries/armem_objects/server/instance/Visu.cpp
index 47206a42fa74036015b875f104c0503172d9ac2e..eb7d90cd267566d10487ce4d2b390ccc63eee586 100644
--- a/source/RobotAPI/libraries/armem_objects/server/instance/Visu.cpp
+++ b/source/RobotAPI/libraries/armem_objects/server/instance/Visu.cpp
@@ -10,7 +10,6 @@
 #include <RobotAPI/libraries/ArmarXObjects/ice_conversions.h>
 #include <RobotAPI/libraries/ArmarXObjects/ObjectFinder.h>
 #include <RobotAPI/libraries/ArmarXObjects/predictions.h>
-#include <RobotAPI/libraries/armem/client/Prediction.h>
 
 
 namespace armarx::armem::server::obj::instance