diff --git a/.clang-format b/.clang-format
index b580ec9ff78e8322008ec834c3ecfd72d8bbc62a..af2e0944734f3c4221734748cf9e721bb040a1b8 100644
--- a/.clang-format
+++ b/.clang-format
@@ -7,3 +7,4 @@ BinPackParameters: false
 BreakBeforeBraces: Allman
 ColumnLimit: 0
 InsertNewlineAtEOF: true
+SeparateDefinitionBlocks: Always
diff --git a/BUILD.bazel b/BUILD.bazel
index d26e88c2fef44b3cf0d6899b8f14a7405c6dceb3..41b9354db4b94cb9d187e74e302ad401668634b2 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -30,6 +30,6 @@ cc_library(
 cc_test(
     name = "interface_test",
     timeout = "short",
-    srcs = ["test/interface_test.cpp"] + glob(["test/**/*.cc"]),
+    srcs = glob(["test/**/*.cc"]),
     deps = [":test_utils"],
 )
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index 5b7684a3eb20e91ffd7fc751b6cf84d62f7c2529..f39e5d5f3a83f9fa96be3c9cd71ed3122156a350 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -1,5 +1,5 @@
 ################################################################################
-# Copyright (c) 2022 Mercedes-Benz Tech Innovation GmbH
+# Copyright (c) 2022-2024 Mercedes-Benz Tech Innovation GmbH
 #               2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
 #
 # This program and the accompanying materials are made available under the terms
@@ -17,6 +17,7 @@ set(DOXYGEN_BUILTIN_STL_SUPPORT YES)
 set(DOXYGEN_DISABLE_INDEX NO)
 set(DOXYGEN_DOT_IMAGE_FORMAT svg)
 set(DOXYGEN_DOT_TRANSPARENT YES)
+set(DOXYGEN_EXCLUDE_SYMBOLS "detail*")
 set(DOXYGEN_FULL_SIDEBAR NO)
 set(DOXYGEN_GENERATE_LATEX NO)
 set(DOXYGEN_GENERATE_TREEVIEW YES)
@@ -40,6 +41,7 @@ set(DOXYGEN_QUIET YES)
 set(DOXYGEN_RECURSIVE YES)
 set(DOXYGEN_TAB_SIZE 2)
 set(DOXYGEN_UML_LOOK YES)
+set(DOXYGEN_USE_MATHJAX YES)
 set(DOXYGEN_USE_MDFILE_AS_MAINPAGE ${PROJECT_SOURCE_DIR}/README.md)
 set(DOXYGEN_WARN_LOGFILE ${CMAKE_CURRENT_BINARY_DIR}/DoxygenWarningLog.txt)
 set(DOXYGEN_WARN_NO_PARAMDOC YES)
diff --git a/include/MantleAPI/Common/bounding_box.h b/include/MantleAPI/Common/bounding_box.h
index 0160dab467e5021a428f6f38986e56ef3fcf3857..7185e80ecd20fbafba8410ad420d772617cd3048 100644
--- a/include/MantleAPI/Common/bounding_box.h
+++ b/include/MantleAPI/Common/bounding_box.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2021-2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -19,27 +20,54 @@
 #include <MantleAPI/Common/vector.h>
 #include <units.h>
 
+#include <iosfwd>
+#include <tuple>
+
 namespace mantle_api
 {
 
+/// Bounding box of an entity.
+///
 /// Each entity has its own local, right-handed coordinate system, where x means "forward" (e.g. driving direction), y means left and z means upwards.
 /// The origin of the entity coordinate system is determined by specifying the offset of the geometric bounding box center in entity coordinates.
 /// For vehicles the origin shall be the center of the rear axis.
 struct BoundingBox
 {
-  Vec3<units::length::meter_t> geometric_center{};  ///< Coordinates of bounding box center in local coordinate system
-  Dimension3 dimension{};                           ///< Dimension of the bounding box (i.e. length = x dimension, width = y dimension, height = z dimension)
+  Vec3<units::length::meter_t> geometric_center;  ///< Coordinates of bounding box center in local coordinate system
+  Dimension3 dimension;                           ///< Dimension of the bounding box (i.e. length = x dimension, width = y dimension, height = z dimension)
 };
 
-/// @brief  equality
-/// @details  Compares the values of two BoundingBoxes.
-/// @param[in]  lhs left-hand side value for the comparison
-/// @param[in]	rhs right-hand side value for the comparison
-/// @returns  true if the values of lhs exactly equal to the values of rhs.
+/// Compare the values of two BoundingBoxes.
+///
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two BoundingBoxes are equal, false otherwise
 constexpr bool operator==(const BoundingBox& lhs, const BoundingBox& rhs) noexcept
 {
-  return lhs.geometric_center == rhs.geometric_center &&
-         lhs.dimension == rhs.dimension;
+  return std::tie(lhs.geometric_center, lhs.dimension) ==
+         std::tie(rhs.geometric_center, rhs.dimension);
+}
+
+/// Compare the values of two BoundingBoxes.
+///
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two BoundingBoxes are not equal, false otherwise
+constexpr bool operator!=(const BoundingBox& lhs, const BoundingBox& rhs) noexcept
+{
+  return !(lhs == rhs);
+}
+
+/// Output stream operator for BoundingBox.
+///
+/// @param[in] os output stream
+/// @param[in] bounding_box BoundingBox to be printed
+/// @returns output stream with printed BoundingBox
+///
+inline std::ostream& operator<<(std::ostream& os, const BoundingBox& bounding_box)
+{
+  os << "BoundingBox(.geometric_center=" << bounding_box.geometric_center << ", .dimension=" << bounding_box.dimension << ')';
+  return os;
 }
 
 }  // namespace mantle_api
diff --git a/include/MantleAPI/Common/dimension.h b/include/MantleAPI/Common/dimension.h
index 16e13c81d15b481bd40fd4e8c504cb20a8d401cf..feb1f7eada2907721a7a4a743d6a55b893bc0060 100644
--- a/include/MantleAPI/Common/dimension.h
+++ b/include/MantleAPI/Common/dimension.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2021-2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -18,37 +19,52 @@
 #include <MantleAPI/Common/floating_point_helper.h>
 #include <units.h>
 
+#include <iosfwd>
+
 namespace mantle_api
 {
 
-/// This struct represents the dimension of the bounding box
+/// Dimension of an object.
 struct Dimension3
 {
-  units::length::meter_t length{0};  ///< Length of the object’s bounding box
-  units::length::meter_t width{0};   ///< Width of the object’s bounding box
-  units::length::meter_t height{0};  ///< Height of the object’s bounding box
+  units::length::meter_t length;  ///< Length of the object
+  units::length::meter_t width;   ///< Width of the object
+  units::length::meter_t height;  ///< Height of the object
 };
 
-/// @brief  almost-equality
-/// @details  Compares the values of two dimensions.
-/// @param[in]  lhs The left-hand side value for the comparison
-/// @param[in]	rhs The right-hand side value for the comparison
-/// @returns  true if the values of lhs almost equal to the values of rhs.
-constexpr bool operator==(const Dimension3& lhs, const Dimension3& rhs) noexcept
+/// Compare the values of two Dimension3.
+///
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two Dimension3 are equal, false otherwise
+constexpr bool
+operator==(const Dimension3& lhs, const Dimension3& rhs) noexcept
 {
-  return AlmostEqual(lhs.length, rhs.length) && AlmostEqual(lhs.width, rhs.width) && AlmostEqual(lhs.height, rhs.height);
+  return AlmostEqual(std::tie(lhs.length, lhs.width, lhs.height), std::tie(rhs.length, rhs.width, rhs.height));
 }
 
-/// @brief  inequality
-/// @details  Compares the value of two dimensions.
-/// @param[in]  lhs left-hand side value for the comparison
-/// @param[in]	rhs right-hand side value for the comparison
-/// @returns  true if the value of lhs is not almost equal to the value of rhs.
+/// Compare the values of two Dimension3.
+///
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two Dimension3 are not equal, false otherwise
 constexpr bool operator!=(const Dimension3& lhs, const Dimension3& rhs) noexcept
 {
   return !(lhs == rhs);
 }
 
+/// Output stream operator for Dimension3.
+///
+/// @param[in] os output stream
+/// @param[in] dimension Dimension3 to be printed
+/// @returns output stream with printed Dimension3
+///
+inline std::ostream& operator<<(std::ostream& os, const Dimension3& dimension)
+{
+  os << "Dimension3(.length=" << dimension.length << ", .width=" << dimension.width << ", .height=" << dimension.height << ')';
+  return os;
+}
+
 }  // namespace mantle_api
 
 #endif  // MANTLEAPI_COMMON_DIMENSION_H
diff --git a/include/MantleAPI/Common/floating_point_helper.h b/include/MantleAPI/Common/floating_point_helper.h
index 4824fa058e0c24288d2a44caef1a3e9a8b63946c..3652c1866e1368335217f2dc5fb5265680fabb54 100644
--- a/include/MantleAPI/Common/floating_point_helper.h
+++ b/include/MantleAPI/Common/floating_point_helper.h
@@ -19,10 +19,12 @@
 #include <units.h>
 
 #include <cmath>
+#include <tuple>
 #include <type_traits>
+#include <utility>
 
 #if !defined(MANTLE_API_DEFAULT_EPS)
-/// @brief Default epsilon for floating-point comparison.
+/// Default epsilon for floating-point comparison.
 ///
 /// > The C++ header `<limits>` provides a constant `std::numeric_limits<float>::epsilon()`
 /// > for this purpose. The “standard” epsilon has the value 1.192092896e-07. This is
@@ -41,7 +43,7 @@ namespace mantle_api
 namespace details
 {
 
-/// @brief The signum function, that returns the sign of a real number
+/// The signum function, that returns the sign of a real number.
 ///
 /// @tparam T the value type
 /// @param[in] value  Real number
@@ -54,11 +56,11 @@ constexpr int signum(const T value) noexcept
 
 }  // namespace details
 
-/// @brief Default epsilon for floating-point comparison.
+/// Default epsilon for floating-point comparison.
 ///
 inline constexpr auto kDefaultEps = MANTLE_API_DEFAULT_EPS;
 
-/// @brief Compare two values for almost-equality.
+/// Compare two values for almost-equality.
 ///
 /// @tparam T the value type
 /// @param[in] lhs The left-hand side value
@@ -105,7 +107,7 @@ constexpr bool AlmostEqual(const T lhs, const T rhs, const T epsilon = static_ca
   return false;
 }
 
-/// @brief Compare two values for greater-or-almost-equality.
+/// Compare two values for greater-or-almost-equality.
 ///
 /// @tparam T the value type
 /// @param[in] lhs The left-hand side value
@@ -124,7 +126,7 @@ constexpr bool GreaterOrEqual(const T lhs, const T rhs, const T epsilon = static
   return AlmostEqual(lhs, rhs, epsilon, absolute_comparison_only);
 }
 
-/// @brief Compare two values for less-or-almost-equality.
+/// Compare two values for less-or-almost-equality.
 ///
 /// @tparam T the value type
 /// @param[in] lhs The left-hand side value
@@ -143,7 +145,7 @@ constexpr bool LessOrEqual(const T lhs, const T rhs, const T epsilon = static_ca
   return AlmostEqual(lhs, rhs, epsilon, absolute_comparison_only);
 }
 
-/// @brief Compare two values for almost-equality.
+/// Compare two values for almost-equality.
 ///
 /// @tparam T the value type
 /// @param[in] lhs The left-hand side value
@@ -157,7 +159,7 @@ constexpr bool AlmostEqual(const T lhs, const T rhs, const T epsilon = T{kDefaul
   return AlmostEqual(lhs(), rhs(), epsilon(), absolute_comparison_only);
 }
 
-/// @brief Compare two values for greater-or-almost-equality.
+/// Compare two values for greater-or-almost-equality.
 ///
 /// @tparam T the value type
 /// @param[in] lhs The left-hand side value
@@ -171,7 +173,7 @@ constexpr bool GreaterOrEqual(const T lhs, const T rhs, const T epsilon = T{kDef
   return GreaterOrEqual(lhs(), rhs(), epsilon(), absolute_comparison_only);
 }
 
-/// @brief Compare two values for less-or-almost-equality.
+/// Compare two values for less-or-almost-equality.
 ///
 /// @tparam T the value type
 /// @param[in] lhs The left-hand side value
@@ -185,6 +187,34 @@ constexpr bool LessOrEqual(const T lhs, const T rhs, const T epsilon = T{kDefaul
   return LessOrEqual(lhs(), rhs(), epsilon(), absolute_comparison_only);
 }
 
+namespace detail
+{
+
+template <typename Tuple, typename T, std::size_t... I>
+constexpr bool AlmostEqualImpl(const Tuple& lhs, const Tuple& rhs, T epsilon, bool absolute_comparison_only, std::index_sequence<I...> /*unused*/)
+{
+  return (AlmostEqual(std::get<I>(lhs), std::get<I>(rhs), std::decay_t<decltype(std::get<I>(lhs))>(epsilon), absolute_comparison_only) && ...);
+}
+
+}  // namespace detail
+
+/// Compare the values of two tuples for almost-equality.
+///
+/// @tparam T the type of epsilon
+/// @tparam Ts the types of the tuple elements
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @param[in] epsilon The epsilon for floating-point comparison
+/// @param[in] absolute_comparison_only True if only absolute comparison should be used to test large numbers' equality
+/// @returns true, if the values of the two tuples are equal, false otherwise
+template <typename T = double, typename... Ts>
+constexpr bool AlmostEqual(const std::tuple<Ts...>& lhs, const std::tuple<Ts...>& rhs,  //
+                           T epsilon = T{kDefaultEps},
+                           bool absolute_comparison_only = false)
+{
+  return detail::AlmostEqualImpl(lhs, rhs, epsilon, absolute_comparison_only, std::index_sequence_for<Ts...>{});
+}
+
 }  // namespace mantle_api
 
 #endif  // MANTLEAPI_COMMON_FLOATING_POINT_HELPER_H
diff --git a/include/MantleAPI/Common/i_identifiable.h b/include/MantleAPI/Common/i_identifiable.h
index 19b9e821376f05325d7af2ba693106b0d9b13fd8..a61eb8460ccd7f68758a6413070ddb413055cc7f 100644
--- a/include/MantleAPI/Common/i_identifiable.h
+++ b/include/MantleAPI/Common/i_identifiable.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2021-2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -16,14 +17,14 @@
 #define MANTLEAPI_COMMON_I_IDENTIFIABLE_H
 
 #include <cstdint>
-#include <limits>
 #include <string>
 
+#include "MantleAPI/Common/identifier.h"
+
 namespace mantle_api
 {
 
-using UniqueId = std::uint64_t;                                      ///< Container for unique id
-constexpr UniqueId InvalidId{std::numeric_limits<UniqueId>::max()};  ///< 'invalid' id
+using UniqueId = Identifier<std::uint64_t, struct UniqueIdTag>;  ///< Unique identifier type
 
 /// Common interface for all classes that can be referenced by an ID or name.
 class IIdentifiable
diff --git a/include/MantleAPI/Common/i_logger.h b/include/MantleAPI/Common/i_logger.h
index 58b6f68406e23c9683393a7671551a552580d50a..7e26858abaa83fafa4458d4dfa1a35f530c1f066 100644
--- a/include/MantleAPI/Common/i_logger.h
+++ b/include/MantleAPI/Common/i_logger.h
@@ -16,6 +16,10 @@
 #ifndef MANTLEAPI_COMMON_I_LOGGER_H
 #define MANTLEAPI_COMMON_I_LOGGER_H
 
+#include <MantleAPI/Common/meta.h>
+
+#include <array>
+#include <cstdint>
 #include <string_view>
 
 /// MantleAPI namespace
@@ -32,7 +36,7 @@ namespace mantle_api
 
 /// Log level definition for ILogger
 /// @ingroup logging
-enum class LogLevel : int
+enum class LogLevel : std::uint8_t
 {
   kTrace = 0,  ///< Step by step execution messages for intensive debugging
   kDebug,      ///< Messages considered to be useful for debugging
@@ -42,6 +46,23 @@ enum class LogLevel : int
   kCritical    ///< Key business functionality is not working, the overall system is impaired
 };
 
+/// Meta info for LogLevel
+template <>
+struct meta::info<LogLevel>
+{
+  /// Get the enumerators of LogLevel
+  /// @return The enumerators of LogLevel
+  [[nodiscard]] static constexpr std::array<meta::enum_info<LogLevel>, 6U> get_enumerators() noexcept
+  {
+    return {{{LogLevel::kTrace, "Trace"},
+             {LogLevel::kDebug, "Debug"},
+             {LogLevel::kInfo, "Info"},
+             {LogLevel::kWarning, "Warning"},
+             {LogLevel::kError, "Error"},
+             {LogLevel::kCritical, "Critical"}}};
+  }
+};
+
 /// Interface for logging messages
 /// @ingroup logging
 class ILogger
diff --git a/include/MantleAPI/Common/identifier.h b/include/MantleAPI/Common/identifier.h
new file mode 100644
index 0000000000000000000000000000000000000000..15fc0b10f94b6162a6d8fa34d6d77e5b6b63739b
--- /dev/null
+++ b/include/MantleAPI/Common/identifier.h
@@ -0,0 +1,310 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+//-----------------------------------------------------------------------------
+/// @file MantleAPI/Common/identifier.h
+//-----------------------------------------------------------------------------
+
+#ifndef MANTLEAPI_COMMON_IDENTIFIER_H
+#define MANTLEAPI_COMMON_IDENTIFIER_H
+
+#include <iosfwd>       // for std::ostream
+#include <limits>       // for std::numeric_limits
+#include <string>       // for std::to_string, std::hash
+#include <type_traits>  // for std::enable_if_t
+#include <utility>      // for std::exchange, std::move, std::swap
+
+/// MantleAPI namespace
+namespace mantle_api
+{
+
+/// Identifier class
+/// @tparam T Type of the identifier
+/// @tparam Tag Tag type
+template <typename T, typename Tag, std::enable_if_t<std::numeric_limits<T>::is_specialized, bool> = true>
+class Identifier
+{
+public:
+  using ValueType = T;  ///< Value type
+  using TagType = Tag;  ///< Tag type
+
+  static constexpr auto kInvalid = std::numeric_limits<ValueType>::max();  ///< Invalid identifier value
+
+  /// Default constructor
+  constexpr Identifier() noexcept = default;
+
+  /// Constructor from value type
+  /// @param value Identifier value
+  constexpr explicit Identifier(ValueType value) noexcept
+      : value_(value) {}
+
+  /// Copy constructor
+  /// @param other Other identifier
+  constexpr Identifier(const Identifier& other) = default;
+
+  /// Move constructor
+  /// @param other Other identifier
+  constexpr Identifier(Identifier&& other) noexcept
+      : value_(std::exchange(other.value_, kInvalid)) {}
+
+  /// Copy assignment operator
+  /// @param other Other identifier
+  /// @return Reference to this
+  constexpr Identifier& operator=(const Identifier& other) noexcept = default;
+
+  /// Copy assignment operator
+  /// @param other Other identifier
+  /// @return Reference to this
+  Identifier& operator=(Identifier& other) noexcept = default;
+
+  /// Move assignment operator
+  /// @param other Other identifier
+  /// @return Reference to this
+  constexpr Identifier& operator=(Identifier&& other) noexcept
+  {
+    value_ = std::exchange(other.value_, kInvalid);
+    return *this;
+  }
+
+  /// Destructor
+  ~Identifier() noexcept = default;
+
+  /// Convert to value type
+  /// @return Value type
+  [[nodiscard]] constexpr ValueType Value() const noexcept
+  {
+    return value_;
+  }
+
+  /// Conversion operator to value type
+  /// @return Value type
+  [[nodiscard]] constexpr explicit operator ValueType() const noexcept
+  {
+    return Value();
+  }
+
+  /// Check if the identifier has a value
+  /// @return True if has a value, false otherwise
+  [[nodiscard]] constexpr bool HasValue() const noexcept
+  {
+    return value_ != kInvalid;
+  }
+
+  /// Conversion operator to bool
+  /// @return True if has a value, false otherwise
+  [[nodiscard]] constexpr explicit operator bool() const noexcept { return HasValue(); }
+
+  /// Assignment operator with value type
+  /// @param value Value type
+  /// @return Reference to this
+  constexpr Identifier& operator=(ValueType&& value) noexcept
+  {
+    value_ = std::move(value);
+    return *this;
+  }
+
+  /// Equality operator
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return True if equal, false otherwise
+  friend constexpr bool operator==(const Identifier& lhs, const Identifier& rhs) noexcept
+  {
+    return lhs.value_ == rhs.value_;
+  }
+
+  /// Inequality operator
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return True if not equal, false otherwise
+  friend constexpr bool operator!=(const Identifier& lhs, const Identifier& rhs) noexcept
+  {
+    return !(lhs == rhs);
+  }
+
+  /// Equality operator with value type
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return True if equal, false otherwise
+  friend constexpr bool operator==(const Identifier& lhs, ValueType rhs) noexcept
+  {
+    return lhs.value_ == rhs;
+  }
+
+  /// Equality operator with value type
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return True if equal, false otherwise
+  friend constexpr bool operator==(ValueType lhs, const Identifier& rhs) noexcept
+  {
+    return rhs.value_ == lhs;
+  }
+
+  /// Inequality operator with value type
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return True if not equal, false otherwise
+  friend constexpr bool operator!=(const Identifier& lhs, ValueType rhs) noexcept
+  {
+    return !(lhs == rhs);
+  }
+
+  /// Inequality operator with value type
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return True if not equal, false otherwise
+  friend constexpr bool operator!=(ValueType lhs, const Identifier& rhs) noexcept
+  {
+    return !(lhs == rhs);
+  }
+
+  /// Less than operator
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return True if less, false otherwise
+  friend constexpr bool operator<(const Identifier& lhs, const Identifier& rhs) noexcept
+  {
+    return lhs.value_ < rhs.value_;
+  }
+
+  /// Less than operator with value type
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return True if less, false otherwise
+  friend constexpr bool operator<(const Identifier& lhs, ValueType rhs) noexcept
+  {
+    return lhs.value_ < rhs;
+  }
+
+  /// Greater than operator
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return True if greater, false otherwise
+  friend constexpr bool operator>(const Identifier& lhs, const Identifier& rhs) noexcept
+  {
+    return rhs < lhs;
+  }
+
+  /// Greater than operator with value type
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return True if greater, false otherwise
+  friend constexpr bool operator>(const Identifier& lhs, ValueType rhs) noexcept
+  {
+    return rhs < lhs.value_;
+  }
+
+  /// Less or equal to operator
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return True if less or equal, false otherwise
+  friend constexpr bool operator<=(const Identifier& lhs, const Identifier& rhs) noexcept
+  {
+    return !(lhs > rhs);
+  }
+
+  /// Less or equal to operator with value type
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return True if less or equal, false otherwise
+  friend constexpr bool operator<=(const Identifier& lhs, ValueType rhs) noexcept
+  {
+    return !(lhs.value_ > rhs);
+  }
+
+  /// Greater or equal to operator
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return True if greater or equal, false otherwise
+  friend constexpr bool operator>=(const Identifier& lhs, const Identifier& rhs) noexcept
+  {
+    return !(lhs < rhs);
+  }
+
+  /// Greater or equal to operator with value type
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return True if greater or equal, false otherwise
+  friend constexpr bool operator>=(const Identifier& lhs, ValueType rhs) noexcept
+  {
+    return !(lhs.value_ < rhs);
+  }
+
+  /// Prefix increment
+  /// @return Reference to this
+  Identifier& operator++() noexcept
+  {
+    value_++;
+    return *this;
+  }
+
+  /// Postfix increment
+  /// @return Reference to this
+  Identifier operator++(int) noexcept
+  {
+    Identifier old = *this;
+    operator++();
+    return old;
+  }
+
+  /// Add operator
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  /// @return Identifier with sum of values of lhs and rhs
+  friend Identifier operator+(Identifier lhs, const Identifier& rhs) noexcept
+  {
+    lhs = lhs.Value() + rhs.Value();
+    return lhs;
+  }
+
+  /// Swap two identifiers
+  /// @param lhs Left-hand side
+  /// @param rhs Right-hand side
+  friend constexpr void swap(Identifier& lhs, Identifier& rhs) noexcept
+  {
+    using std::swap;
+    swap(lhs.value_, rhs.value_);
+  }
+
+  /// Output stream operator
+  /// @param os Output stream
+  /// @param identifier Identifier
+  /// @return Output stream
+  friend inline std::ostream& operator<<(std::ostream& os, const Identifier& identifier)
+  {
+    return os << std::to_string(identifier.Value());
+  }
+
+private:
+  ValueType value_{kInvalid};  ///< Identifier value
+};
+
+}  // namespace mantle_api
+
+namespace std
+{
+
+/// Hash specialization for mantle_api::Identifier
+/// @tparam T Type of the identifier
+/// @tparam Tag Tag type
+template <typename T, typename Tag>
+struct hash<mantle_api::Identifier<T, Tag>>
+{
+  /// Hash function
+  /// @param identifier Identifier
+  /// @return Hash value
+  size_t operator()(const mantle_api::Identifier<T, Tag>& identifier) const
+  {
+    return hash<T>{}(identifier.Value());
+  }
+};
+
+}  // namespace std
+
+#endif  // MANTLEAPI_COMMON_IDENTIFIER_H
diff --git a/include/MantleAPI/Common/log_utils.h b/include/MantleAPI/Common/log_utils.h
deleted file mode 100644
index f0293e5f882d20cda7ca557519576200c18d6d85..0000000000000000000000000000000000000000
--- a/include/MantleAPI/Common/log_utils.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2023, Mercedes-Benz Tech Innovation GmbH
- * Copyright (c) 2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
- *
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- *******************************************************************************/
-
-//-----------------------------------------------------------------------------
-/// @file MantleAPI/Common/log_utils.h
-//-----------------------------------------------------------------------------
-
-#ifndef MANTLEAPI_COMMON_LOG_UTILS_H
-#define MANTLEAPI_COMMON_LOG_UTILS_H
-
-#include <MantleAPI/Common/i_logger.h>
-
-#include <array>
-#include <cstddef>
-#include <ostream>
-#include <string_view>
-
-/// MantleAPI namespace
-namespace mantle_api
-{
-
-/// Log utilities namespace
-namespace log_utils
-{
-
-/// Array of log level names
-/// @ingroup logging
-static inline constexpr auto kLogLevelNames = std::array<std::string_view, 6U>{"Trace", "Debug", "Info", "Warning", "Error", "Critical"};
-
-/// Convert a log level to its name
-/// @param[in] level The log level
-/// @return The name of the log level
-/// @ingroup logging
-[[nodiscard]] constexpr std::string_view ToStringView(LogLevel level) noexcept
-{
-  return (level >= LogLevel::kTrace && level <= LogLevel::kCritical) ? kLogLevelNames.at(static_cast<std::size_t>(level)) : "Log level out of range";
-}
-
-}  // namespace log_utils
-
-/// Stream operator for log level
-/// @param[in] os The output stream
-/// @param[in] level The log level
-/// @return The output stream
-/// @ingroup logging
-inline std::ostream& operator<<(std::ostream& os, mantle_api::LogLevel level) noexcept
-{
-  os << log_utils::ToStringView(level);
-  return os;
-}
-
-}  // namespace mantle_api
-
-#endif  // MANTLEAPI_COMMON_LOG_UTILS_H
diff --git a/include/MantleAPI/Common/meta.h b/include/MantleAPI/Common/meta.h
new file mode 100644
index 0000000000000000000000000000000000000000..9626659aa85b9b722839df0426f4a35538a3babc
--- /dev/null
+++ b/include/MantleAPI/Common/meta.h
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+//-----------------------------------------------------------------------------
+/// @file meta.h
+//-----------------------------------------------------------------------------
+
+#ifndef MANTLEAPI_COMMON_META_H
+#define MANTLEAPI_COMMON_META_H
+
+#include <cstddef>
+#include <iosfwd>
+#include <optional>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+
+namespace mantle_api
+{
+
+namespace meta
+{
+
+namespace details
+{
+
+template <typename InputIt, typename UnaryPredicate>
+constexpr InputIt find_if(InputIt first, InputIt last, UnaryPredicate&& pred) noexcept
+{
+  while (first != last)
+  {
+    if (std::forward<UnaryPredicate>(pred)(*first))
+    {
+      return first;
+    }
+    ++first;
+  }
+  return last;
+}
+
+}  // namespace details
+
+/// Structure to hold the meta info of an enum value
+///
+/// @tparam T The enum type
+template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
+struct enum_info
+{
+  T value;                ///< The enum value
+  std::string_view name;  ///< The name of the enum value
+};
+
+/// Primary template for info
+template <typename T, typename Enable = void>
+struct info
+{
+  info() = delete;
+};
+
+/// Helper template to check for the presence of info<T>::get_enumerators
+template <typename, typename = std::void_t<>>
+struct has_meta_info : std::false_type
+{
+};
+
+/// Helper template to check for the presence of info<T>::get_enumerators
+template <typename T>
+struct has_meta_info<T, std::void_t<decltype(&info<T>::get_enumerators)>> : std::true_type
+{
+};
+
+/// Helper variable template to check for the presence of info<T>::get_enumerators
+template <typename T>
+inline constexpr bool has_meta_info_v = has_meta_info<T>::value;
+
+/// Helper variable template to check if T is an enum with info<T>::get_enumerators
+template <typename T>
+inline constexpr bool is_enum_with_meta_info_v = std::is_enum_v<T> && has_meta_info_v<T>;
+
+/// Helper function to get the enumerators of an enum type
+///
+/// @tparam T The enum type
+/// @return The enumerators of the enum type
+template <typename T, typename = std::enable_if_t<is_enum_with_meta_info_v<T>>>
+[[nodiscard]] inline constexpr auto enumerators_of(T /*unused*/ = T{}) noexcept
+{
+  return info<T>::get_enumerators();
+}
+
+/// Helper function to get the size of the enum type
+///
+/// @tparam T The enum type
+/// @return The size of the enum type
+template <typename T, typename = std::enable_if_t<is_enum_with_meta_info_v<T>>>
+[[nodiscard]] inline constexpr std::size_t size_of(T /*unused*/ = T{}) noexcept
+{
+  return enumerators_of(T{}).size();
+}
+
+/// Get the value of the enum_info
+///
+/// @tparam T The enum type
+/// @param enumerator The enum_info
+/// @return The value of the enum_info
+template <typename T, typename = std::enable_if_t<is_enum_with_meta_info_v<T>>>
+[[nodiscard]] inline constexpr T value_of(const enum_info<T>& enumerator) noexcept
+{
+  return enumerator.value;
+}
+
+/// Get the name of the enum_info
+///
+/// @tparam T The enumeration type
+/// @param enumerator The enum_info
+/// @return The name of the enum_info
+template <typename T, typename = std::enable_if_t<is_enum_with_meta_info_v<T>>>
+[[nodiscard]] inline constexpr std::string_view name_of(const enum_info<T>& enumerator) noexcept
+{
+  return enumerator.name;
+}
+
+/// Get the name of the enum value
+///
+/// @tparam T The enum type
+/// @param value The enum value
+/// @return The name of the enum value
+template <typename T, typename = std::enable_if_t<is_enum_with_meta_info_v<T>>>
+[[nodiscard]] inline constexpr std::string_view enum_to_string(const T value) noexcept
+{
+  const auto enumerators = enumerators_of(T{});
+  const auto it = details::find_if(enumerators.begin(), enumerators.end(), [value](const auto& enumerator) noexcept
+                                   { return value_of(enumerator) == value; });
+  if (it == enumerators.end())
+  {
+    return {};
+  }
+  return name_of(*it);
+}
+
+/// Get the enum value from the name
+///
+/// @tparam T The enum type
+/// @param name The name of the enum value
+/// @return The enum value
+template <typename T, typename = std::enable_if_t<is_enum_with_meta_info_v<T>>>
+[[nodiscard]] inline constexpr std::optional<T> string_to_enum(const std::string_view name) noexcept
+{
+  if (name.empty())
+  {
+    return std::nullopt;
+  }
+
+  const auto enumerators = enumerators_of(T{});
+  const auto it = details::find_if(enumerators.begin(), enumerators.end(), [&name](const auto& enumerator)
+                                   { return name_of(enumerator) == name; });
+  if (it == enumerators.end())
+  {
+    return std::nullopt;
+  }
+  return value_of(*it);
+}
+
+}  // namespace meta
+
+/// Output stream operator for enum values
+///
+/// @tparam CharT The character type
+/// @tparam Traits The character traits
+/// @tparam T The enum type
+/// @param os The output stream
+/// @param value The enum value
+/// @return The output stream
+template <typename CharT, typename Traits, typename T, typename = std::enable_if_t<meta::is_enum_with_meta_info_v<T>>>
+inline std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const T value) noexcept
+{
+  os << meta::enum_to_string(value);
+  return os;
+}
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_COMMON_META_H
diff --git a/include/MantleAPI/Common/orientation.h b/include/MantleAPI/Common/orientation.h
index 432bdc11114e158553fbdda08da5d5437efbbcdb..20387579d3d3b5eab02bd5b0892cee1f759e6ad5 100644
--- a/include/MantleAPI/Common/orientation.h
+++ b/include/MantleAPI/Common/orientation.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2021-2024, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -19,80 +20,84 @@
 #include <MantleAPI/Common/unit_definitions.h>
 #include <units.h>
 
+#include <iosfwd>
+#include <type_traits>
+
 namespace mantle_api
 {
 
+/// Definition of the orientation in terms of the Yaw/Pitch/Roll orientation angles in the Cartesian coordinate system
 template <typename T,
           class = typename std::enable_if_t<units::traits::is_angle_unit<T>::value ||
                                             units::traits::is_angular_velocity_unit<T>::value ||
                                             units::traits::is_angular_acceleration_unit<T>::value>>
-
-/// Definition of the orientation in terms of the Yaw/Pitch/Roll orientation angles in the Cartesian coordinate system
 struct Orientation3
 {
-  Orientation3() = default;
-
-  /// Constructor
-  ///
-  /// @param[in] yaw_in   yaw angle
-  /// @param[in] pitch_in pitch angle
-  /// @param[in] roll_in  roll angle
-  Orientation3(T yaw_in, T pitch_in, T roll_in)
-      : yaw{yaw_in}, pitch{pitch_in}, roll{roll_in}
-  {
-  }
-
-  T yaw{};    ///< Yaw represents the rotation around the vertical axis (heading angle)
-  T pitch{};  ///< Pitch represents the rotation around the lateral axis (elevation angle)
-  T roll{};   ///< Roll represents the rotation around the longitudinal axis (bank angle)
+  T yaw;    ///< Yaw represents the rotation around the vertical axis (heading angle)
+  T pitch;  ///< Pitch represents the rotation around the lateral axis (elevation angle)
+  T roll;   ///< Roll represents the rotation around the longitudinal axis (bank angle)
 };
 
-/// @brief  almost-equality
-/// @details  Compares the values of two orientations.
+/// Compare the values of two Orientation3.
+///
 /// @tparam T the value type
-/// @param[in]  lhs The left-hand side value for the comparison
-/// @param[in]	rhs The right-hand side value for the comparison
-/// @returns  true if the values of lhs almost equal to the values of rhs.
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two Orientation3 are equal, false otherwise
 template <typename T>
 constexpr bool operator==(const Orientation3<T>& lhs, const Orientation3<T>& rhs) noexcept
 {
-  return AlmostEqual(lhs.yaw, rhs.yaw) && AlmostEqual(lhs.pitch, rhs.pitch) && AlmostEqual(lhs.roll, rhs.roll);
+  return AlmostEqual(std::tie(lhs.yaw, lhs.pitch, lhs.roll), std::tie(rhs.yaw, rhs.pitch, rhs.roll));
 }
 
-/// @brief  inequality
-/// @details  Compares the value of two orientations.
+/// Compare the values of two Orientation3.
+///
 /// @tparam T the value type
-/// @param[in]  lhs left-hand side value for the comparison
-/// @param[in]	rhs right-hand side value for the comparison
-/// @returns  true if the value of lhs is not almost equal to the value of rhs.
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two Orientation3 are not equal, false otherwise
 template <typename T>
 constexpr bool operator!=(const Orientation3<T>& lhs, const Orientation3<T>& rhs) noexcept
 {
   return !(lhs == rhs);
 }
 
-/// @brief addition
-/// @details Returns the sum of two orientations
+/// Add two Orientation3.
+///
 /// @tparam T the value type
-/// @param[in]  lhs left-hand side value for the sum
-/// @param[in]	rhs right-hand side value for the sum
-/// @returns sum of lhs and rhs.
+/// @param[in] lhs left-hand side value for the sum
+/// @param[in] rhs right-hand side value for the sum
+/// @returns sum of lhs and rhs
 template <typename T>
 constexpr Orientation3<T> operator+(const Orientation3<T>& lhs, const Orientation3<T>& rhs) noexcept
 {
-  return Orientation3<T>{lhs.yaw + rhs.yaw, lhs.pitch + rhs.pitch, lhs.roll + rhs.roll};
+  return {lhs.yaw + rhs.yaw, lhs.pitch + rhs.pitch, lhs.roll + rhs.roll};
 }
 
-/// @brief subtraction
-/// @details Returns the difference of two orientations
+/// Subtract two Orientation3.
+///
 /// @tparam T the value type
-/// @param[in]  lhs left-hand side value for the difference
-/// @param[in]	rhs right-hand side value for the difference
-/// @returns difference of lhs and rhs.
+/// @param[in] lhs left-hand side value for the difference
+/// @param[in] rhs right-hand side value for the difference
+/// @returns difference of lhs and rhs
 template <typename T>
 constexpr Orientation3<T> operator-(const Orientation3<T>& lhs, const Orientation3<T>& rhs) noexcept
 {
-  return Orientation3<T>{lhs.yaw - rhs.yaw, lhs.pitch - rhs.pitch, lhs.roll - rhs.roll};
+  return {lhs.yaw - rhs.yaw, lhs.pitch - rhs.pitch, lhs.roll - rhs.roll};
+}
+
+/// Output stream operator for Orientation3.
+///
+/// @tparam T the value type
+/// @param[in] os output stream
+/// @param[in] orientation Orientation3 to be printed
+/// @returns output stream with printed Orientation3
+///
+template <typename T>
+inline std::ostream& operator<<(std::ostream& os, const Orientation3<T>& orientation)
+{
+  os << "Orientation3(.yaw=" << orientation.yaw << ", .pitch=" << orientation.pitch << ", .roll=" << orientation.roll << ')';
+  return os;
 }
 
 }  // namespace mantle_api
diff --git a/include/MantleAPI/Common/pose.h b/include/MantleAPI/Common/pose.h
index 5bbaf6a5f6c68152384474a96c3514d767f81ea9..e497012e38354f3e9b124640824c30b98fef3452 100644
--- a/include/MantleAPI/Common/pose.h
+++ b/include/MantleAPI/Common/pose.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2021-2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -19,50 +20,50 @@
 #include <MantleAPI/Common/vector.h>
 #include <units.h>
 
-#include <iostream>
+#include <iosfwd>
+#include <tuple>
 
 namespace mantle_api
 {
 
-/// Pose in the Cartesian coordinate system
+/// Pose in the Cartesian coordinate system.
 struct Pose
 {
   /// Position defined in terms of the x/y/z coordinates in the Cartesian coordinate system
-  Vec3<units::length::meter_t> position{};
+  Vec3<units::length::meter_t> position;
   /// Orientation defined in terms of the Yaw/Pitch/Roll orientation angles in the Cartesian coordinate system
-  Orientation3<units::angle::radian_t> orientation{};
-
-  /// @brief Equality comparison for Pose.
-  ///
-  /// @param[in]  other The left-hand side value for the comparison
-  /// @returns  true if the values of `this` exactly equal to the values of other.
-  bool operator==(const Pose& other) const
-  {
-    return other.position == position && other.orientation == orientation;
-  }
-
-  /// @brief Prints a human-readable representation of 'pose' to 'os'.
-  /// @param os     The output stream
-  /// @param pose   Open scenario pose
-  /// @returns 'pose' in a human-readable format
-  friend inline std::ostream& operator<<(std::ostream& os, const Pose& pose);
+  Orientation3<units::angle::radian_t> orientation;
 };
 
-/// @brief Prints a human-readable representation of 'pose' to 'os'.
-/// @param os     The output stream
-/// @param pose   Open scenario pose
-/// @returns 'pose' in a human-readable format
-std::ostream& operator<<(std::ostream& os, const Pose& pose)
+/// Compare the values of two Poses.
+///
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two Poses are equal, false otherwise
+constexpr bool operator==(const Pose& lhs, const Pose& rhs) noexcept
 {
-  os << "position ("
-     << pose.position.x
-     << ", " << pose.position.y
-     << ", " << pose.position.z
-     << "), orientation (" << pose.orientation.yaw
-     << ", " << pose.orientation.pitch
-     << ", " << pose.orientation.roll
-     << ")";
+  return std::tie(lhs.position, lhs.orientation) == std::tie(rhs.position, rhs.orientation);
+}
 
+/// Compare the values of two Poses.
+///
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two Poses are not equal, false otherwise
+constexpr bool operator!=(const Pose& lhs, const Pose& rhs) noexcept
+{
+  return !(lhs == rhs);
+}
+
+/// Output stream operator for Pose.
+///
+/// @param[in] os output stream
+/// @param[in] pose Pose to be printed
+/// @returns output stream with printed Pose
+///
+inline std::ostream& operator<<(std::ostream& os, const Pose& pose)
+{
+  os << "Pose(.position=" << pose.position << ", .orientation=" << pose.orientation << ')';
   return os;
 }
 
diff --git a/include/MantleAPI/Common/position.h b/include/MantleAPI/Common/position.h
index 6e9dc2c1bbc4573eed4dec2e3b8d18880355a968..ca993c4feb9edb1ffc2c25f0841e8b68afc41f39 100644
--- a/include/MantleAPI/Common/position.h
+++ b/include/MantleAPI/Common/position.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2021-2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -20,116 +21,162 @@
 #include <units.h>
 
 #include <cstdint>
+#include <iosfwd>
 #include <string>
 #include <variant>
 
 namespace mantle_api
 {
 
-/// Position defined in terms of the road coordinates (t,s) applied to a given road as defined in OpenDRIVE
+/// Position in the OpenDRIVE Road coordinate system.
+///
+/// This position is determined by a road id as defined in OpenDRIVE, and an offset in s and t direction w.r.t. the road reference line.
 struct OpenDriveRoadPosition
 {
-  /// @brief RoadId as defined in OpenDRIVE
-  std::string road{};
-  /// @brief Offset in s direction w.r.t. road, unit: [m]
-  units::length::meter_t s_offset{0.0};
-  /// @brief Offset in t direction w.r.t. reference line of road, unit: [m]
-  units::length::meter_t t_offset{0.0};
+  std::string road;                 ///< RoadId as defined in OpenDRIVE
+  units::length::meter_t s_offset;  ///< Offset in longitudinal direction w.r.t. the road reference line, unit: [m]
+  units::length::meter_t t_offset;  ///< Offset in lateral direction w.r.t. the road reference line, unit: [m]
 };
 
-/// Position that is determined by a lane (lane ID as defined in OpenDRIVE) and the s coordinate of a given road
+/// Position in the OpenDRIVE Lane coordinate system.
+///
+/// This position is determined by a road and lane id as defined in OpenDRIVE, and an offset in s and t direction w.r.t. the lane center line.
 struct OpenDriveLanePosition
 {
-  /// @brief RoadId as defined in OpenDRIVE
-  std::string road{};
-  /// @brief LaneId as defined in OpenDRIVE (e.g. -1 for right lane)
-  std::int32_t lane{0};
-  /// @brief Offset in s direction w.r.t lane (same as road), unit: [m]
-  units::length::meter_t s_offset{0.0};
-  /// @brief Offset in t direction w.r.t center line of lane, unit: [m]
-  units::length::meter_t t_offset{0.0};
+  std::string road;                 ///< RoadId as defined in OpenDRIVE
+  std::int32_t lane;                ///< LaneId as defined in OpenDRIVE (e.g. -1 for right lane)
+  units::length::meter_t s_offset;  ///< Offset in longitudinal direction w.r.t lane center line, unit: [m]
+  units::length::meter_t t_offset;  ///< Offset in lateral direction w.r.t lane center line, unit: [m]
 };
 
-/// Position defined in terms of the spherical geographic coordinates (angular Longitude and Latitude)
+/// Position in the spherical geographic coordinate system.
+///
+/// This position is defined in terms of the latitude and longitude in the spherical geographic coordinate system.
 struct LatLonPosition
 {
-  /// @brief GPS latitude, unit: [rad]
-  units::angle::radian_t latitude{0.0};
-  /// @brief GPS longitude, unit: [rad]
-  units::angle::radian_t longitude{0.0};
+  units::angle::radian_t latitude;   ///< GPS latitude, unit: [rad]
+  units::angle::radian_t longitude;  ///< GPS longitude, unit: [rad]
 };
 
-/// Variant of possible definitions of position (e.g. in terms of the road coordinates, spherical geographic coordinates etc.)
+/// A variant type for different position representations.
 using Position = std::variant<OpenDriveRoadPosition, OpenDriveLanePosition, LatLonPosition, Vec3<units::length::meter_t>>;
 
-/// @brief Equality comparison for OpenDriveRoadPosition.
+/// Compare the values of two OpenDriveRoadPositions.
 ///
-/// **Attention** Floating-point comparision may require tweaks in precision.
-/// @param[in]  lhs The left-hand side value for the comparison
-/// @param[in]	rhs The right-hand side value for the comparison
-/// @returns  true if the values of lhs (almost) equal to the values of rhs.
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two OpenDriveRoadPositions are equal, false otherwise
+/// @note The floating-point comparision may require tweaks in precision.
 inline bool operator==(const OpenDriveRoadPosition& lhs, const OpenDriveRoadPosition& rhs) noexcept
 {
   return lhs.road == rhs.road &&
-         AlmostEqual(lhs.s_offset, rhs.s_offset) &&
-         AlmostEqual(lhs.t_offset, rhs.t_offset);
+         AlmostEqual(std::tie(lhs.s_offset, lhs.t_offset), std::tie(rhs.s_offset, rhs.t_offset));
 }
 
-/// @brief  Inequality comparison for OpenDriveLanePosition.
+/// Compare the values of two OpenDriveRoadPositions.
 ///
-/// @param[in]  lhs left-hand side value for the comparison
-/// @param[in]	rhs right-hand side value for the comparison
-/// @returns  true if the value of lhs is not almost equal to the value of rhs.
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two OpenDriveRoadPositions are not equal, false otherwise
 inline bool operator!=(const OpenDriveRoadPosition& lhs, const OpenDriveRoadPosition& rhs) noexcept
 {
   return !(lhs == rhs);
 }
 
-/// @brief Equality comparison for OpenDriveLanePosition.
+/// Compare the values of two OpenDriveLanePositions.
 ///
-/// **Attention** Floating-point comparision may require tweaks in precision.
-/// @param[in]  lhs The left-hand side value for the comparison
-/// @param[in]	rhs The right-hand side value for the comparison
-/// @returns  true if the values of lhs (almost) equal to the values of rhs.
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two OpenDriveLanePositions are equal, false otherwise
+/// @note The floating-point comparision may require tweaks in precision.
 inline bool operator==(const OpenDriveLanePosition& lhs, const OpenDriveLanePosition& rhs) noexcept
 {
   return lhs.road == rhs.road &&
          lhs.lane == rhs.lane &&
-         AlmostEqual(lhs.s_offset, rhs.s_offset) &&
-         AlmostEqual(lhs.t_offset, rhs.t_offset);
+         AlmostEqual(std::tie(lhs.s_offset, lhs.t_offset), std::tie(rhs.s_offset, rhs.t_offset));
 }
 
-/// @brief  Inequality comparison for OpenDriveLanePosition.
+/// Compare the values of two OpenDriveLanePositions.
 ///
-/// @param[in]  lhs left-hand side value for the comparison
-/// @param[in]	rhs right-hand side value for the comparison
-/// @returns  true if the value of lhs is not almost equal to the value of rhs.
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two OpenDriveLanePositions are not equal, false otherwise
 inline bool operator!=(const OpenDriveLanePosition& lhs, const OpenDriveLanePosition& rhs) noexcept
 {
   return !(lhs == rhs);
 }
 
-/// @brief Equality comparison for LatLonPosition.
+/// Compare the values of two LatLonPositions.
 ///
-/// **Attention** Floating-point comparision may require tweaks in precision.
-/// @param[in]  lhs The left-hand side value for the comparison
-/// @param[in]	rhs The right-hand side value for the comparison
-/// @returns  true if the values of lhs almost equal to the values of rhs.
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two LatLonPositions are equal, false otherwise
+/// @note The floating-point comparision may require tweaks in precision.
 constexpr bool operator==(const LatLonPosition& lhs, const LatLonPosition& rhs) noexcept
 {
-  return AlmostEqual(lhs.latitude, rhs.latitude) && AlmostEqual(lhs.longitude, rhs.longitude);
+  return AlmostEqual(std::tie(lhs.latitude, lhs.longitude), std::tie(rhs.latitude, rhs.longitude));
 }
 
-/// @brief  Inequality comparison for LatLonPosition.
+/// Compare the values of two LatLonPositions.
 ///
-/// @param[in]  lhs left-hand side value for the comparison
-/// @param[in]	rhs right-hand side value for the comparison
-/// @returns  true if the value of lhs is not almost equal to the value of rhs.
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two LatLonPositions are not equal, false otherwise
 constexpr bool operator!=(const LatLonPosition& lhs, const LatLonPosition& rhs) noexcept
 {
   return !(lhs == rhs);
 }
 
+/// Output stream operator for OpenDriveRoadPosition.
+///
+/// @param[in] os output stream
+/// @param[in] position OpenDriveRoadPosition to be printed
+/// @returns output stream with printed OpenDriveRoadPosition
+///
+inline std::ostream& operator<<(std::ostream& os, const OpenDriveRoadPosition& position)
+{
+  os << "OpenDriveRoadPosition(.road=" << position.road << ", .s_offset=" << position.s_offset << ", .t_offset=" << position.t_offset << ')';
+  return os;
+}
+
+/// Output stream operator for OpenDriveLanePosition.
+///
+/// @param[in] os output stream
+/// @param[in] position OpenDriveLanePosition to be printed
+/// @returns output stream with printed OpenDriveLanePosition
+///
+inline std::ostream& operator<<(std::ostream& os, const OpenDriveLanePosition& position)
+{
+  os << "OpenDriveLanePosition(.road=" << position.road << ", .lane=" << position.lane << ", .s_offset=" << position.s_offset << ", .t_offset=" << position.t_offset << ')';
+  return os;
+}
+
+/// Output stream operator for LatLonPosition.
+///
+/// @param[in] os output stream
+/// @param[in] position LatLonPosition to be printed
+/// @returns output stream with printed LatLonPosition
+///
+inline std::ostream& operator<<(std::ostream& os, const LatLonPosition& position)
+{
+  os << "LatLonPosition(.latitude=" << position.latitude << ", .longitude=" << position.longitude << ')';
+  return os;
+}
+
+/// Output stream operator for Position.
+///
+/// @param[in] os output stream
+/// @param[in] position Position to be printed
+/// @returns output stream with printed Position
+///
+inline std::ostream& operator<<(std::ostream& os, const Position& position)
+{
+  std::visit([&os](const auto& pos)
+             { os << pos; },
+             position);
+  return os;
+}
+
 }  // namespace mantle_api
 
 #endif  // MANTLEAPI_COMMON_POSITION_H
diff --git a/include/MantleAPI/Common/route_definition.h b/include/MantleAPI/Common/route_definition.h
deleted file mode 100644
index 6dfc890b46465cfb1a19509d344d945977bfbe2e..0000000000000000000000000000000000000000
--- a/include/MantleAPI/Common/route_definition.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2022-2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
- * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
- *
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- *******************************************************************************/
-
-//-----------------------------------------------------------------------------
-/// @file route_definition.h
-//-----------------------------------------------------------------------------
-
-#ifndef MANTLEAPI_COMMON_ROUTE_DEFINITION_H
-#define MANTLEAPI_COMMON_ROUTE_DEFINITION_H
-
-#include <MantleAPI/Common/vector.h>
-#include <units.h>
-
-#include <tuple>
-#include <vector>
-
-namespace mantle_api
-{
-
-/// Define how the route from a waypoint forward should be calculated.
-enum class RouteStrategy
-{
-  kUndefined = 0,
-  kFastest,
-  kLeastIntersections,
-  kShortest
-};
-
-/// Group a Waypoint with a RouteStrategy.
-struct RouteWaypoint
-{
-  /// Reference position used to form a route
-  mantle_api::Vec3<units::length::meter_t> waypoint{};
-  /// Defines how a route should be calculated
-  RouteStrategy route_strategy{};
-};
-
-/// Equality comparison for RouteWaypoint.
-///
-/// @param[in] lhs The left-hand side value for the comparison
-/// @param[in] rhs The right-hand side value for the comparison
-/// @returns true if the values of lhs and rhs are equal
-inline bool operator==(const RouteWaypoint& lhs, const RouteWaypoint& rhs) noexcept
-{
-  return std::tie(lhs.waypoint, lhs.route_strategy) == std::tie(rhs.waypoint, rhs.route_strategy);
-}
-
-/// Inequality comparison for RouteWaypoint.
-///
-/// @param[in] lhs The left-hand side value for the comparison
-/// @param[in] rhs The right-hand side value for the comparison
-/// @returns true if the values of lhs and rhs are not equal
-inline bool operator!=(const RouteWaypoint& lhs, const RouteWaypoint& rhs) noexcept
-{
-  return !(lhs == rhs);
-}
-
-/// A raw set of global coordinates and information for
-/// linking them, from which the actual route can be calculated.
-struct RouteDefinition
-{
-  /// The list of waypoints with associated RouteStrategies
-  std::vector<mantle_api::RouteWaypoint> waypoints;
-};
-
-/// Equality comparison for RouteDefinition.
-///
-/// @param[in] lhs The left-hand side value for the comparison
-/// @param[in] rhs The right-hand side value for the comparison
-/// @returns true if the values of lhs and rhs are equal
-inline bool operator==(const RouteDefinition& lhs, const RouteDefinition& rhs) noexcept
-{
-  return lhs.waypoints == rhs.waypoints;
-}
-
-/// Inequality comparison for RouteDefinition.
-///
-/// @param[in] lhs The left-hand side value for the comparison
-/// @param[in] rhs The right-hand side value for the comparison
-/// @returns true if the values of lhs and rhs are not equal
-inline bool operator!=(const RouteDefinition& lhs, const RouteDefinition& rhs) noexcept
-{
-  return !(lhs == rhs);
-}
-
-}  // namespace mantle_api
-
-#endif  // MANTLEAPI_COMMON_ROUTE_DEFINITION_H
diff --git a/include/MantleAPI/Common/spline.h b/include/MantleAPI/Common/spline.h
index 250e7d6f335fdbab68190aec7015699e97a8ca72..04a5a6356a61f98c4db1526e44e8d741c6b26533 100644
--- a/include/MantleAPI/Common/spline.h
+++ b/include/MantleAPI/Common/spline.h
@@ -1,6 +1,7 @@
 
 /*******************************************************************************
  * Copyright (c) 2021-2024, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -17,64 +18,153 @@
 #define MANTLEAPI_COMMON_SPLINE_H
 
 #include <MantleAPI/Common/floating_point_helper.h>
-#include <MantleAPI/Common/orientation.h>
 #include <MantleAPI/Common/time_utils.h>
-#include <MantleAPI/Common/unit_definitions.h>
 #include <MantleAPI/Common/vector.h>
 #include <units.h>
 
+#include <iosfwd>
 #include <tuple>
 
 namespace mantle_api
 {
 
-/// Definition of a spline segment represented by the polynomial parameters a, b, c, d
+/// Definition of a spline segment represented by the polynomial parameters a, b, c, d.
+///
 /// @tparam T Type of polynomial parameters
 template <typename T>
 struct SplineSegment
 {
-  Vec3<T> a;  ///< Polynom parameter a, e.g. unit: [m]
-  Vec3<T> b;  ///< Polynom parameter b, e.g. unit: [1/m]
-  Vec3<T> c;  ///< Polynom parameter c, e.g. unit: [1/m²]
-  Vec3<T> d;  ///< Polynom parameter d, e.g. unit: [1/m³]
+  Vec3<T> a;  ///< Polynomial parameter a, e.g. unit: [m]
+  Vec3<T> b;  ///< Polynomial parameter b, e.g. unit: [1/m]
+  Vec3<T> c;  ///< Polynomial parameter c, e.g. unit: [1/m²]
+  Vec3<T> d;  ///< Polynomial parameter d, e.g. unit: [1/m³]
 };
 
-/// Definition of the section of the spline curve
+/// Compare the values of two SplineSegments.
+///
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two SplineSegments are equal, false otherwise
+template <typename T>
+constexpr bool operator==(const SplineSegment<T>& lhs, const SplineSegment<T>& rhs) noexcept
+{
+  return std::tie(lhs.a, lhs.b, lhs.c, lhs.d) == std::tie(rhs.a, rhs.b, rhs.c, rhs.d);
+}
+
+/// Compare the values of two SplineSegments.
+///
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two SplineSegments are not equal, false otherwise
+template <typename T>
+constexpr bool operator!=(const SplineSegment<T>& lhs, const SplineSegment<T>& rhs) noexcept
+{
+  return !(lhs == rhs);
+}
+
+/// Definition of the section of the spline curve.
+///
 /// @tparam T the value type
 template <typename T, class = typename std::enable_if_t<units::traits::is_unit<T>::value>>
 struct SplineSection
 {
-  /// Time specification at the start of the section of the spline curve
-  Time start_time{0};
-  /// Time specification at the end of the section of the spline curve
-  Time end_time{0};
-  /// @brief Represents the polynomial.
-  ///
-  /// The tuple stores in format \f$[a_3, a_2, a_1, a_0]\f$ for a polynomial in form
-  /// @f[
-  ///   P(x) = \sum_{i=0}^{3} a_{i} x^{i} = a_3 x^3 + a_2 x^2 + a_1 x + a_0
-  /// @f]
-  std::tuple<units::unit_t<units::compound_unit<T, units::inverse<units::cubed<units::time::second>>>>,
-             units::unit_t<units::compound_unit<T, units::inverse<units::squared<units::time::second>>>>,
-             units::unit_t<units::compound_unit<T, units::inverse<units::time::second>>>,
-             units::unit_t<T>>
-      polynomial{
-          units::unit_t<units::compound_unit<T, units::inverse<units::cubed<units::time::second>>>>(0),
-          units::unit_t<units::compound_unit<T, units::inverse<units::squared<units::time::second>>>>(0),
-          units::unit_t<units::compound_unit<T, units::inverse<units::time::second>>>(0),
-          units::unit_t<T>(0)};
+  /// Definition of a polynomial in form \f$P(x) = a_3 x^3 + a_2 x^2 + a_1 x + a_0\f$.
+  struct Polynomial
+  {
+    using A3Type = units::unit_t<units::compound_unit<T, units::inverse<units::cubed<units::time::second>>>>;    ///< Type of polynomial parameter a3
+    using A2Type = units::unit_t<units::compound_unit<T, units::inverse<units::squared<units::time::second>>>>;  ///< Type of polynomial parameter a2
+    using A1Type = units::unit_t<units::compound_unit<T, units::inverse<units::time::second>>>;                  ///< Type of polynomial parameter a1
+    using A0Type = units::unit_t<T>;                                                                             ///< Type of polynomial parameter a0
+
+    A3Type a3;  ///< Polynomial parameter a3
+    A2Type a2;  ///< Polynomial parameter a2
+    A1Type a1;  ///< Polynomial parameter a1
+    A0Type a0;  ///< Polynomial parameter a0
+
+    /// Compare the values of two Polynomials.
+    ///
+    /// @param[in] other right-hand side value for the comparison
+    /// @returns true, if the values of the two Polynomials are almost equal, false otherwise
+    constexpr bool operator==(const Polynomial& other) const noexcept
+    {
+      return AlmostEqual(std::tie(a3, a2, a1, a0), std::tie(other.a3, other.a2, other.a1, other.a0));
+    }
+
+    /// Compare the values of two Polynomials.
+    ///
+    /// @param[in] other right-hand side value for the comparison
+    /// @returns true, if the values of the two Polynomials are not almost equal, false otherwise
+    constexpr bool operator!=(const Polynomial& other) const noexcept
+    {
+      return !(*this == other);
+    }
+
+    /// Output stream operator for Polynomial.
+    ///
+    /// @param[in] os output stream
+    /// @param[in] polynomial Polynomial to be printed
+    /// @returns output stream with printed Polynomial
+    ///
+    friend std::ostream& operator<<(std::ostream& os, const Polynomial& polynomial)
+    {
+      os << "Polynomial(.a3=" << polynomial.a3 << ", .a2=" << polynomial.a2 << ", .a1=" << polynomial.a1 << ", .a0=" << polynomial.a0 << ')';
+      return os;
+    }
+  };
+
+  Time start_time;        ///< Time specification at the start of the section of the spline curve
+  Time end_time;          ///< Time specification at the end of the section of the spline curve
+  Polynomial polynomial;  ///< Polynomial parameters of the spline curve
 };
 
-/// @brief Equality comparison for SplineSection.
+/// Compare the values of two SplineSections.
 ///
-/// @tparam T the value type
-/// @param[in]  lhs The left-hand side value for the comparison
-/// @param[in]	rhs The right-hand side value for the comparison
-/// @returns  true if the values of lhs (almost) equal to the values of rhs.
-template <typename T, class = typename std::enable_if_t<units::traits::is_unit<T>::value>>
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two SplineSections are equal, false otherwise
+template <typename T>
 constexpr bool operator==(const SplineSection<T>& lhs, const SplineSection<T>& rhs) noexcept
 {
-  return lhs.start_time == rhs.start_time && lhs.end_time == rhs.end_time && AlmostEqual(std::get<0>(lhs.polynomial), std::get<0>(rhs.polynomial)) && AlmostEqual(std::get<1>(lhs.polynomial), std::get<1>(rhs.polynomial)) && AlmostEqual(std::get<2>(lhs.polynomial), std::get<2>(rhs.polynomial)) && AlmostEqual(std::get<3>(lhs.polynomial), std::get<3>(rhs.polynomial));
+  return std::tie(lhs.start_time, lhs.end_time, lhs.polynomial) == std::tie(rhs.start_time, rhs.end_time, rhs.polynomial);
+}
+
+/// Compare the values of two SplineSections.
+///
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two SplineSections are not equal, false otherwise
+template <typename T>
+constexpr bool operator!=(const SplineSection<T>& lhs, const SplineSection<T>& rhs) noexcept
+{
+  return !(lhs == rhs);
+}
+
+/// Output stream operator for SplineSegment.
+///
+/// @tparam T the value type
+/// @param[in] os output stream
+/// @param[in] segment SplineSegment to be printed
+/// @returns output stream with printed SplineSegment
+///
+template <typename T>
+inline std::ostream& operator<<(std::ostream& os, const SplineSegment<T>& segment)
+{
+  os << "SplineSegment(.a=" << segment.a << ", .b=" << segment.b << ", .c=" << segment.c << ", .d=" << segment.d << ')';
+  return os;
+}
+
+/// Output stream operator for SplineSection.
+///
+/// @tparam T the value type
+/// @param[in] os output stream
+/// @param[in] section SplineSection to be printed
+/// @returns output stream with printed SplineSection
+///
+template <typename T>
+inline std::ostream& operator<<(std::ostream& os, const SplineSection<T>& section)
+{
+  os << "SplineSection(.start_time=" << section.start_time << ", .end_time=" << section.end_time << ", .polynomial=" << section.polynomial << ')';
+  return os;
 }
 
 }  // namespace mantle_api
diff --git a/include/MantleAPI/Common/trajectory.h b/include/MantleAPI/Common/trajectory.h
index e4598bef778f4cc4c07466a5f9e10bf18b2cada3..7c56de4638b761f85a3aaeacc8028deaac83e2d9 100644
--- a/include/MantleAPI/Common/trajectory.h
+++ b/include/MantleAPI/Common/trajectory.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2021-2025, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -18,8 +19,7 @@
 #include <MantleAPI/Common/clothoid_spline.h>
 #include <MantleAPI/Common/poly_line.h>
 
-#include <cstdint>
-#include <optional>
+#include <iosfwd>
 #include <string>
 #include <tuple>
 #include <variant>
@@ -37,7 +37,7 @@ enum class TrajectoryReferencePoint : std::uint8_t
   kBoundingBoxCenter  ///< Reference point is the center of the bounding box of the object
 };
 
-/// Definition of a trajectory type in terms of shape
+/// Definition of a trajectory type in terms of shape.
 struct Trajectory
 {
   std::string name;                             ///< Name of the trajectory type
@@ -45,21 +45,32 @@ struct Trajectory
   TrajectoryReferencePoint reference;           ///< Reference point of object, which is used in trajectory
 };
 
-/// Compare two objects of Trajectory.
+/// Compare the values of two Trajectory objects.
 ///
-/// @param[in]  lhs left-hand side value for the comparison
-/// @param[in]  rhs right-hand side value for the comparison
-/// @returns  true if the values of lhs exactly equals to rhs values
-constexpr bool operator==(const Trajectory& lhs, const Trajectory& rhs) noexcept
+/// @param lhs left-hand side Trajectory object
+/// @param rhs right-hand side Trajectory object
+/// @return true if the Trajectory objects are equal, false otherwise
+inline bool operator==(const Trajectory& lhs, const Trajectory& rhs) noexcept
 {
   return std::tie(lhs.name, lhs.type, lhs.reference) == std::tie(rhs.name, rhs.type, rhs.reference);
 }
 
-/// Print a human-readable representation of 'trajectory' to 'os'.
+/// Compare the values of two Trajectory objects.
+///
+/// @param lhs left-hand side Trajectory object
+/// @param rhs right-hand side Trajectory object
+/// @return true if the Trajectory objects are not equal, false otherwise
+inline bool operator!=(const Trajectory& lhs, const Trajectory& rhs) noexcept
+{
+  return !(lhs == rhs);
+}
+
+/// Output stream operator for Trajectory.
+///
+/// @param os output stream
+/// @param trajectory Trajectory to be printed
+/// @return output stream with printed Trajectory
 ///
-/// @param os         The output stream
-/// @param trajectory Open scenario trajectory
-/// @returns 'trajectory' in a human-readable format
 inline std::ostream& operator<<(std::ostream& os, const Trajectory& trajectory)
 {
   os << "Trajectory(.name=" << trajectory.name << ", .type=";
diff --git a/include/MantleAPI/Common/vector.h b/include/MantleAPI/Common/vector.h
index 8b878f51cd1f3668dd5152c9fac62b664100fcc6..51b2ad92be4efe0edf3ddd6607640ccf00e6929b 100644
--- a/include/MantleAPI/Common/vector.h
+++ b/include/MantleAPI/Common/vector.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2021-2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -16,98 +17,94 @@
 #define MANTLEAPI_COMMON_VECTOR_H
 
 #include <MantleAPI/Common/floating_point_helper.h>
+#include <units.h>
+
+#include <iosfwd>
+#include <tuple>
+#include <type_traits>
 
 namespace mantle_api
 {
 
+/// 3-dimensional vector in the right-handed Cartesian coordinate system.
 template <typename T, class = typename std::enable_if_t<units::traits::is_unit_t<T>::value>>
-
-/// 3-dimensional vector that contains three components (x, y, z) in the right-handed Cartesian coordinate system
 struct Vec3
 {
-  Vec3() = default;
-
-  /// Constructor
-  ///
-  /// @param[in] x_in  x-value
-  /// @param[in] y_in  y-value
-  /// @param[in] z_in  z-value
-  Vec3(T x_in, T y_in, T z_in)
-      : x{x_in}, y{y_in}, z{z_in}
-  {
-  }
+  T x;  ///< x-component
+  T y;  ///< y-component
+  T z;  ///< z-component
 
-  T x{0};  ///< x-component
-  T y{0};  ///< y-component
-  T z{0};  ///< z-component
-
-  /// @brief Returns length of the vector
+  /// Calculate the length of the vector.
   ///
-  /// @returns length of the vector
+  /// @returns the length of the vector
   inline T Length() const { return units::math::sqrt((x * x) + (y * y) + (z * z)); }
 
-  /// @brief Changes the sign of the 3d vector
+  /// Change the sign of the vector.
   ///
-  /// @returns 3d vector
-  inline Vec3<T> operator-() const noexcept
+  /// @returns the vector with the sign changed
+  constexpr Vec3 operator-() const noexcept
   {
     return {-x, -y, -z};
   }
 };
 
-/// @brief  almost-equality
-/// @details  Compares the values of two 3d vectors.
+/// Deduction guide for Vec3.
+template <typename T>
+Vec3(T, T, T) -> Vec3<T>;
+
+/// Compare the values of two Vec3.
+///
 /// @tparam T the value type
-/// @param[in]  lhs The left-hand side value for the comparison
-/// @param[in]	rhs The right-hand side value for the comparison
-/// @returns  true if the values of lhs almost equal to the values of rhs.
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two Vec3 are equal, false otherwise
 template <typename T>
 constexpr bool operator==(const Vec3<T>& lhs, const Vec3<T>& rhs) noexcept
 {
-  return AlmostEqual(lhs.x, rhs.x) && AlmostEqual(lhs.y, rhs.y) && AlmostEqual(lhs.z, rhs.z);
+  return AlmostEqual(std::tie(lhs.x, lhs.y, lhs.z), std::tie(rhs.x, rhs.y, rhs.z));
 }
 
-/// @brief  inequality
-/// @details  Compares the value of two 3d vectors.
+/// Compare the values of two Vec3.
+///
 /// @tparam T the value type
-/// @param[in]  lhs left-hand side value for the comparison
-/// @param[in]	rhs right-hand side value for the comparison
-/// @returns  true if the value of lhs is not almost equal to the value of rhs.
+/// @param[in] lhs left-hand side value for the comparison
+/// @param[in] rhs right-hand side value for the comparison
+/// @returns true, if the values of the two Vec3 are not equal, false otherwise
 template <typename T>
 constexpr bool operator!=(const Vec3<T>& lhs, const Vec3<T>& rhs) noexcept
 {
   return !(lhs == rhs);
 }
 
-/// @brief subtraction
-/// @details Returns the difference of two 3d vectors
+/// Add two Vec3.
+///
 /// @tparam T the value type
-/// @param[in]  lhs left-hand side value for the difference
-/// @param[in]	rhs right-hand side value for the difference
-/// @returns difference of lhs and rhs.
+/// @param[in] lhs left-hand side value for the sum
+/// @param[in] rhs right-hand side value for the sum
+/// @returns the sum of the two Vec3
 template <typename T>
-constexpr Vec3<T> operator-(const Vec3<T>& lhs, const Vec3<T>& rhs) noexcept
+constexpr Vec3<T> operator+(const Vec3<T>& lhs, const Vec3<T>& rhs) noexcept
 {
-  return {lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z};
+  return {lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z};
 }
 
-/// @brief addition
-/// @details Returns the sum of two 3d vectors
+/// Subtract two Vec3.
+///
 /// @tparam T the value type
-/// @param[in]  lhs left-hand side value for the sum
-/// @param[in]	rhs right-hand side value for the sum
-/// @returns sum of lhs and rhs.
+/// @param[in] lhs left-hand side value for the difference
+/// @param[in] rhs right-hand side value for the difference
+/// @returns the difference of the two Vec3
 template <typename T>
-constexpr Vec3<T> operator+(const Vec3<T>& lhs, const Vec3<T>& rhs) noexcept
+constexpr Vec3<T> operator-(const Vec3<T>& lhs, const Vec3<T>& rhs) noexcept
 {
-  return {lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z};
+  return {lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z};
 }
 
-/// @brief multiplication
-/// @details Multiplication by a scalar for 3d vector
+/// Multiply a Vec3 by a scalar.
+///
 /// @tparam T the value type
-/// @param[in]  lhs left-hand side value for the multiplication
-/// @param[in]	d   scalar
+/// @param[in] lhs left-hand side value for the multiplication
+/// @param[in] d scalar for the multiplication
 /// @returns the scalar multiplied vector
 template <typename T>
 constexpr Vec3<T> operator*(const Vec3<T>& lhs, double d) noexcept
@@ -115,11 +112,11 @@ constexpr Vec3<T> operator*(const Vec3<T>& lhs, double d) noexcept
   return {lhs.x * d, lhs.y * d, lhs.z * d};
 }
 
-/// @brief multiplication
-/// @details Multiplication by a scalar for 3d vector
+/// Multiply a scalar by a Vec3.
+///
 /// @tparam T the value type
-/// @param[in]	d   scalar
-/// @param[in]	rhs right-hand side value for the multiplication
+/// @param[in] d scalar for the multiplication
+/// @param[in] rhs right-hand side value for the multiplication
 /// @returns the scalar multiplied vector
 template <typename T>
 constexpr Vec3<T> operator*(double d, const Vec3<T>& rhs) noexcept
@@ -127,24 +124,24 @@ constexpr Vec3<T> operator*(double d, const Vec3<T>& rhs) noexcept
   return rhs * d;
 }
 
-/// @brief division
-/// @details Division by a scalar for 3d vector
+/// Divide a Vec3 by a scalar.
+///
 /// @tparam T the value type
-/// @param[in]  lhs left-hand side value for the division
-/// @param[in]	d   scalar
-/// @returns the lhs divided by d
+/// @param[in] lhs left-hand side value for the division
+/// @param[in] d scalar for the division
+/// @returns the scalar divided vector
 template <typename T>
 constexpr Vec3<T> operator/(const Vec3<T>& lhs, double d) noexcept
 {
   return {lhs.x / d, lhs.y / d, lhs.z / d};
 }
 
-/// @brief addable
-/// @details Add a 3d vector to a 3d vector
+/// AddAssign two Vec3.
+///
 /// @tparam T the value type
-/// @param[in]  lhs left-hand side value
-/// @param[in]	rhs right-hand side value, which will be added
-/// @returns the lhs where rhs is added
+/// @param[in] lhs left-hand side value for the sum
+/// @param[in] rhs right-hand side value for the sum
+/// @returns lhs after adding rhs
 template <typename T>
 constexpr Vec3<T> operator+=(Vec3<T>& lhs, const Vec3<T>& rhs) noexcept
 {
@@ -154,12 +151,12 @@ constexpr Vec3<T> operator+=(Vec3<T>& lhs, const Vec3<T>& rhs) noexcept
   return lhs;
 }
 
-/// @brief subtractable
-/// @details Subtract a 3d vector from a 3d vector
+/// SubtractAssign two Vec3.
+///
 /// @tparam T the value type
-/// @param[in]  lhs left-hand side value
-/// @param[in]	rhs right-hand side value
-/// @returns the lhs from where rhs is subtracted
+/// @param[in] lhs left-hand side value for the difference
+/// @param[in] rhs right-hand side value for the difference
+/// @returns lhs after subtracting rhs
 template <typename T>
 constexpr Vec3<T> operator-=(Vec3<T>& lhs, const Vec3<T>& rhs) noexcept
 {
@@ -169,14 +166,14 @@ constexpr Vec3<T> operator-=(Vec3<T>& lhs, const Vec3<T>& rhs) noexcept
   return lhs;
 }
 
-/// @brief addable
-/// @details Add a scalar to a 3d vector
+/// AddAssign a scalar to each component of a Vec3.
+///
 /// @tparam T the value type
-/// @param[in]  lhs left-hand side value
-/// @param[in]	d   scalar
-/// @returns the lhs where d is added
+/// @param[in] lhs left-hand side value for the sum
+/// @param[in] d scalar for the sum
+/// @returns lhs after adding d to each component
 template <typename T>
-constexpr Vec3<T> operator+=(Vec3<T>& lhs, double d) noexcept
+constexpr Vec3<T> operator+=(Vec3<T>& lhs, T d) noexcept
 {
   lhs.x += d;
   lhs.y += d;
@@ -184,14 +181,14 @@ constexpr Vec3<T> operator+=(Vec3<T>& lhs, double d) noexcept
   return lhs;
 }
 
-/// @brief subtractable
-/// @details Subtract a scalar from a 3d vector
-/// @tparam     T   Type of vector components
-/// @param[in]  lhs left-hand side value
-/// @param[in]	d   scalar
-/// @returns the lhs from where d is subtracted
+/// SubtractAssign a scalar from each component of a Vec3.
+///
+/// @tparam T the value type
+/// @param[in] lhs left-hand side value for the difference
+/// @param[in] d scalar for the difference
+/// @returns lhs after subtracting d from each component
 template <typename T>
-constexpr Vec3<T> operator-=(Vec3<T>& lhs, double d) noexcept
+constexpr Vec3<T> operator-=(Vec3<T>& lhs, T d) noexcept
 {
   lhs.x -= d;
   lhs.y -= d;
@@ -199,6 +196,20 @@ constexpr Vec3<T> operator-=(Vec3<T>& lhs, double d) noexcept
   return lhs;
 }
 
+/// Output stream operator for Vec3.
+///
+/// @tparam T the value type
+/// @param[in] os output stream
+/// @param[in] vector Vec3 to be printed
+/// @returns output stream with printed Vec3
+///
+template <typename T>
+inline std::ostream& operator<<(std::ostream& os, const Vec3<T>& vector)
+{
+  os << "Vec3(.x=" << vector.x << ", .y=" << vector.y << ", .z=" << vector.z << ')';
+  return os;
+}
+
 }  // namespace mantle_api
 
 #endif  // MANTLEAPI_COMMON_VECTOR_H
diff --git a/include/MantleAPI/EnvironmentalConditions/weather.h b/include/MantleAPI/EnvironmentalConditions/weather.h
index af3200b090c44b76664c4d134d45b1bf876c639c..df6587e8072d58eae1719e3fe2dd1b4cb0a5ee55 100644
--- a/include/MantleAPI/EnvironmentalConditions/weather.h
+++ b/include/MantleAPI/EnvironmentalConditions/weather.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2021-2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -17,52 +18,54 @@
 
 #include <units.h>
 
+#include <cstdint>
+
 namespace mantle_api
 {
 
 /// Specify the amount of the precipitation.
-enum class Precipitation
+enum class Precipitation : std::uint8_t
 {
-  kUnknown,
-  kOther,
-  kNone,
-  kVeryLight,
-  kLight,
-  kModerate,
-  kHeavy,
-  kVeryHeavy,
-  kExtreme
+  kUnknown = 0,  ///< The amount of precipitation is unknown.
+  kOther,        ///< The amount of precipitation is known, but unspecified.
+  kNone,         ///< There is no precipitation.
+  kVeryLight,    ///< There is very light precipitation.
+  kLight,        ///< There is light precipitation.
+  kModerate,     ///< There is moderate precipitation.
+  kHeavy,        ///< There is heavy precipitation.
+  kVeryHeavy,    ///< There is very heavy precipitation.
+  kExtreme       ///< There is extreme precipitation.
 };
 
 /// Specify the amount of the fog.
-enum class Fog
+enum class Fog : std::uint8_t
 {
-  kUnknown,
-  kOther,
-  kExcellentVisibility,
-  kGoodVisibility,
-  kModerateVisibility,
-  kPoorVisibility,
-  kMist,
-  kLight,
-  kThick,
-  kDense
+  kUnknown = 0,          ///< The amount of fog is unknown.
+  kOther,                ///< The amount of fog is known, but unspecified.
+  kExcellentVisibility,  ///< Visibility is excellent. There is no fog.
+  kGoodVisibility,       ///< Visibility is good. There is light fog.
+  kModerateVisibility,   ///< Visibility is moderate. There is thick fog.
+  kPoorVisibility,       ///< Visibility is poor. There is dense fog.
+  kMist,                 ///< Visibility is moderate. It is misty.
+  kLight,                ///< Visibility is good. There is light fog.
+  kThick,                ///< Visibility is moderate. There is thick fog.
+  kDense                 ///< Visibility is poor. There is dense fog.
 };
 
 /// Specify the level of illumination.
-enum class Illumination
+enum class Illumination : std::uint8_t
 {
-  kUnknown,
-  kOther,
-  kLevel1,
-  kLevel2,
-  kLevel3,
-  kLevel4,
-  kLevel5,
-  kLevel6,
-  kLevel7,
-  kLevel8,
-  kLevel9
+  kUnknown = 0,  ///< The level of illumination is unknown.
+  kOther,        ///< The level of illumination is known, but unspecified.
+  kLevel1,       ///< The level of illumination is 1.
+  kLevel2,       ///< The level of illumination is 2.
+  kLevel3,       ///< The level of illumination is 3.
+  kLevel4,       ///< The level of illumination is 4.
+  kLevel5,       ///< The level of illumination is 5.
+  kLevel6,       ///< The level of illumination is 6.
+  kLevel7,       ///< The level of illumination is 7.
+  kLevel8,       ///< The level of illumination is 8.
+  kLevel9        ///< The level of illumination is 9.
 };
 
 /// Specification of sun properties.
diff --git a/include/MantleAPI/Execution/i_environment.h b/include/MantleAPI/Execution/i_environment.h
index 3837f85873ddadfedf28aa0bbf26dc790ff12fa6..06de70a8d07a8113a63d5608e5be1f224fb9979a 100644
--- a/include/MantleAPI/Execution/i_environment.h
+++ b/include/MantleAPI/Execution/i_environment.h
@@ -17,12 +17,12 @@
 #define MANTLEAPI_EXECUTION_I_ENVIRONMENT_H
 
 #include <MantleAPI/Common/i_geometry_helper.h>
-#include <MantleAPI/Common/route_definition.h>
 #include <MantleAPI/Common/time_utils.h>
 #include <MantleAPI/EnvironmentalConditions/road_condition.h>
 #include <MantleAPI/EnvironmentalConditions/weather.h>
 #include <MantleAPI/Map/i_coord_converter.h>
 #include <MantleAPI/Map/i_lane_location_query_service.h>
+#include <MantleAPI/Map/i_route_repository.h>
 #include <MantleAPI/Map/map_details.h>
 #include <MantleAPI/Traffic/default_routing_behavior.h>
 #include <MantleAPI/Traffic/i_controller_repository.h>
@@ -31,6 +31,7 @@
 #include <MantleAPI/Traffic/i_traffic_swarm_service.h>
 
 #include <cstdint>
+#include <memory>
 #include <optional>
 #include <string>
 #include <variant>
@@ -39,7 +40,7 @@ namespace mantle_api
 {
 
 /// @brief Allowed data types for parameters defined in a parameter declaration.
-using ParameterType = std::variant<bool, mantle_api::Time, double, std::string, std::uint32_t, std::uint16_t, std::int32_t>;
+using ParameterType = std::variant<bool, Time, double, std::string, std::uint32_t, std::uint16_t, std::int32_t>;
 
 /// Base interface for the environment conditions (e.g. time of day, weather, road condition) of a scenario
 class IEnvironment
@@ -53,7 +54,7 @@ public:
   ///                             environment must do so.
   /// @param map_details          Area of the map
   /// @param map_model_reference  File path of a 3D model representing the virtual environment
-  virtual void CreateMap(const std::string& map_file_path, const mantle_api::MapDetails& map_details, const std::string& map_model_reference) = 0;
+  virtual void CreateMap(const std::string& map_file_path, const MapDetails& map_details, const std::string& map_model_reference) = 0;
 
   /// Assigns an entity to the specified controller. This controller needs to be created beforehand.
   ///
@@ -72,14 +73,14 @@ public:
   /// @param entity_id          Specifies the entity to be updated
   /// @param control_strategies Specifies the desired movement behavior for the entity
   virtual void UpdateControlStrategies(
-      UniqueId entity_id, std::vector<std::shared_ptr<mantle_api::ControlStrategy>> control_strategies) = 0;
+      UniqueId entity_id, std::vector<std::shared_ptr<ControlStrategy>> control_strategies) = 0;
 
   /// Checks, if a control strategy of a certain type for a specific entity has been fulfilled
   ///
   /// @param entity_id    The entity to check
   /// @param type         The control strategy type
   /// @return true if a control strategy of a certain type for a specific entity has been fulfilled
-  [[nodiscard]] virtual bool HasControlStrategyGoalBeenReached(UniqueId entity_id, mantle_api::ControlStrategyType type) const = 0;
+  [[nodiscard]] virtual bool HasControlStrategyGoalBeenReached(UniqueId entity_id, ControlStrategyType type) const = 0;
 
   /// @brief Retrieves the ILaneLocationQueryService that provides abstraction layer for all map related functions
   ///
@@ -116,20 +117,30 @@ public:
   /// @return const reference to the controller repository interface
   [[nodiscard]] virtual const IControllerRepository& GetControllerRepository() const = 0;
 
+  /// @brief Retrieves the route repository that provides CRUD functionality for routes
+  ///
+  /// @return const reference to the route repository interface
+  [[nodiscard]] virtual IRouteRepository& GetRouteRepository() = 0;
+
+  /// @brief Retrieves the route repository that provides CRUD functionality for routes
+  ///
+  /// @return const reference to the route repository interface
+  [[nodiscard]] virtual const IRouteRepository& GetRouteRepository() const = 0;
+
   /// @brief Sets the DateTime in UTC (converted from RFC 3339 standard)
   ///
   /// @param time Time in ms
-  virtual void SetDateTime(mantle_api::Time time) = 0;
+  virtual void SetDateTime(Time time) = 0;
 
   /// @brief Gets the DateTime in UTC
   ///
   /// @return time in ms
-  virtual mantle_api::Time GetDateTime() = 0;
+  virtual Time GetDateTime() = 0;
 
   /// @brief Gets the time since start of simulation
   ///
   /// @return time since start of simulation in ms
-  virtual mantle_api::Time GetSimulationTime() = 0;
+  virtual Time GetSimulationTime() = 0;
 
   /// @brief Sets the weather conditions
   ///
@@ -164,7 +175,7 @@ public:
   ///
   /// @param name  The name of the user defined value
   /// @return The user defined value. No value if it doesn't exist.
-  virtual std::optional<std::string> GetUserDefinedValue(const std::string& name) = 0;
+  [[nodiscard]] virtual std::optional<std::string> GetUserDefinedValue(const std::string& name) const = 0;
 
   /// @brief Sets a named variable
   ///
@@ -182,13 +193,7 @@ public:
   ///        or if an entity has reached the end of a route
   ///
   /// @param default_routing_behavior   selects the behavior
-  virtual void SetDefaultRoutingBehavior(mantle_api::DefaultRoutingBehavior default_routing_behavior) = 0;
-
-  /// Assigns a route to an entity
-  ///
-  /// @param entity_id         specifies the entity
-  /// @param route_definition  specifies how the route shall be constructed
-  virtual void AssignRoute(mantle_api::UniqueId entity_id, mantle_api::RouteDefinition route_definition) = 0;
+  virtual void SetDefaultRoutingBehavior(DefaultRoutingBehavior default_routing_behavior) = 0;
 
   /// @brief Initializes the traffic swarm service with the scenario parameters
   ///
diff --git a/include/MantleAPI/Map/i_coord_converter.h b/include/MantleAPI/Map/i_coord_converter.h
index 6bbc8e43a79f33f7799a83ed1aaf1954aebf0c2b..0d878d95aff798b7d0bf1ccbd6deb5695bac587a 100644
--- a/include/MantleAPI/Map/i_coord_converter.h
+++ b/include/MantleAPI/Map/i_coord_converter.h
@@ -30,20 +30,20 @@ class ICoordConverter
 public:
   virtual ~ICoordConverter() = default;
 
-  /// Converts a position of any kind to its corresponding inertial position.
+  /// Convert a position of any kind to its corresponding inertial position.
   ///
   /// @param position The input position. Coordinate system is implicitly defined by underlying type of Position
   /// @return Inertial position
   [[nodiscard]] virtual Vec3<units::length::meter_t> Convert(Position position) = 0;
 
-  /// Calculates the orientation of the lane center line at a given lane position.
+  /// Calculate the orientation of the lane center line at a given lane position.
   ///
   /// @param open_drive_lane_position Position specified in a lane coordinate system (road id, local lane id, s)
   /// @return Orientation of the lane center line at the specified position in inertial coordinates
   [[nodiscard]] virtual Orientation3<units::angle::radian_t> GetLaneOrientation(
       const OpenDriveLanePosition& open_drive_lane_position) = 0;
 
-  /// Calculates the orientation of the road reference line at a given road position.
+  /// Calculate the orientation of the road reference line at a given road position.
   ///
   /// @param open_drive_road_position Position specified in a road coordinate system (road id, s)
   /// @return Orientation of the road reference line at the specified position in inertial coordinates
diff --git a/include/MantleAPI/Map/i_lane_location_query_service.h b/include/MantleAPI/Map/i_lane_location_query_service.h
index 73687219d34ab13c17a0bcb0891802466cb7059a..9cecc0edb238e7884e2cc78cd190a52d1efca591 100644
--- a/include/MantleAPI/Map/i_lane_location_query_service.h
+++ b/include/MantleAPI/Map/i_lane_location_query_service.h
@@ -1,6 +1,7 @@
 /*******************************************************************************
  * Copyright (c) 2021-2025, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
  * Copyright (c) 2022 Ansys, Inc.
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -23,6 +24,7 @@
 #include <MantleAPI/Map/lane_definition.h>
 #include <units.h>
 
+#include <cstdint>
 #include <optional>
 #include <vector>
 
@@ -30,19 +32,19 @@ namespace mantle_api
 {
 
 /// Specifiy the direction of the lane relative to the reference pose.
-enum class Direction
+enum class Direction : std::uint8_t
 {
-  kForward = 0,
-  kBackwards = 1
+  kForward = 0,  ///< The lane has the same direction as the reference pose.
+  kBackwards     ///< The lane has the opposite direction of the reference pose.
 };
 
 /// Definiton of the lateral displacement direction either to the left or right w.r.t the reference pose.
 /// "Any" means that the position calculation to the left is executed first and, in case of an an invalid result, to the right next.
-enum class LateralDisplacementDirection
+enum class LateralDisplacementDirection : std::uint8_t
 {
-  kAny = 0,
-  kLeft = 1,
-  kRight = 2
+  kAny = 0,  ///< The lateral displacement direction is not specified.
+  kLeft,     ///< The lateral displacement direction is to the left.
+  kRight     ///< The lateral displacement direction is to the right.
 };
 
 /// Abstraction layer for all map related functions.
@@ -121,8 +123,8 @@ public:
   /// @return Position at the given lateral distance in the given displacement direction from the reference pose.
   ///         If the calculated position is not on a lane, no value is returned. If the position is on multiple
   ///         lanes at the same time, the first lane in the list is considered.
-  [[nodiscard]] virtual std::optional<Vec3<units::length::meter_t>> GetPosition(const mantle_api::Pose& reference_pose,
-                                                                                mantle_api::LateralDisplacementDirection direction,
+  [[nodiscard]] virtual std::optional<Vec3<units::length::meter_t>> GetPosition(const Pose& reference_pose,
+                                                                                LateralDisplacementDirection direction,
                                                                                 units::length::meter_t distance) const = 0;
 
   /// @brief Calculate the longitudinal distance of two given positions on a lane.
@@ -135,8 +137,8 @@ public:
   ///         No value returned if the distance is not calculable.
 
   [[nodiscard]] virtual std::optional<units::length::meter_t> GetLongitudinalLaneDistanceBetweenPositions(
-      const mantle_api::Vec3<units::length::meter_t>& start_position,
-      const mantle_api::Vec3<units::length::meter_t>& target_position) const = 0;
+      const Vec3<units::length::meter_t>& start_position,
+      const Vec3<units::length::meter_t>& target_position) const = 0;
 
   /// @brief Calculate a new pose which is at a certain longitudinal distance in a relative lane from the
   ///        reference_pose_on_lane.
@@ -166,8 +168,8 @@ public:
   /// @return Lane id that is at the given lateral shift (relative_lane_target) from given position
   ///         (reference_pose_on_lane). No value, if reference pose is not on a lane or if the lane doesn't have a
   ///         suitable adjacent lane.
-  [[nodiscard]] virtual std::optional<mantle_api::LaneId> GetRelativeLaneId(const mantle_api::Pose& reference_pose_on_lane,
-                                                                            int relative_lane_target) const = 0;
+  [[nodiscard]] virtual std::optional<LaneId> GetRelativeLaneId(const Pose& reference_pose_on_lane,
+                                                                int relative_lane_target) const = 0;
 
   /// @brief Calculate pose projected from a given position to a target lane centerline
   ///
@@ -175,8 +177,8 @@ public:
   /// @param target_lane_id  The id of the target lane that the reference position is projected to.
   /// @return The projected pose on the target lane centerline. No value, if the projection pose cannot be calculated,
   /// e.g. reference position not projectable, or target lane does not exist, etc.
-  [[nodiscard]] virtual std::optional<mantle_api::Pose> GetProjectedPoseAtLane(const Vec3<units::length::meter_t>& reference_position_on_lane,
-                                                                               mantle_api::LaneId target_lane_id) const = 0;
+  [[nodiscard]] virtual std::optional<Pose> GetProjectedPoseAtLane(const Vec3<units::length::meter_t>& reference_position_on_lane,
+                                                                   UniqueId target_lane_id) const = 0;
 
   /// @brief Tries to map a given position to a lane and then returns the projected center line point of the lane from the
   /// given position
diff --git a/include/MantleAPI/Map/i_route.h b/include/MantleAPI/Map/i_route.h
index 80357e6910983a0b5d21b74feeaa756fe5963983..99cb4d7a7fdf1bac76df3e605cfcf06754557b19 100644
--- a/include/MantleAPI/Map/i_route.h
+++ b/include/MantleAPI/Map/i_route.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2021-2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -16,61 +17,46 @@
 #define MANTLEAPI_MAP_I_ROUTE_H
 
 #include <MantleAPI/Common/i_identifiable.h>
+#include <MantleAPI/Common/position.h>
 #include <MantleAPI/Common/vector.h>
 #include <MantleAPI/Map/lane_definition.h>
+#include <optional>
 #include <units.h>
 
 namespace mantle_api
 {
 
-/// Base interface for route
-/// It represents continuous path throughout the road network, defined by a series of waypoints
+/// Base interface for routes.
+/// It represents a path through the road network, following the reference lines of road tracks.
 class IRoute : public virtual IIdentifiable
 {
 public:
-  /// Adds a waypoint to the route
+  /// Check whether the route is looped.
+  /// A looped route connects the end with the start of a route resulting in a repeatably drivable path.
   ///
-  /// @param inert_pos Waypoint to add
-  /// @return created route defined by a series of waypoints
-  virtual IRoute& AddWaypoint(const Vec3<units::length::meter_t>& inert_pos) = 0;
+  /// @return true, if the route is looped, otherwise false
+  [[nodiscard]] virtual bool IsLooped() const = 0;
 
-  /// Adds a waypoint to the route
+  /// Return a road position along the route reference line given a longitudinal and lateral offset.
+  /// If the provided longitudinal offset is longer than the length of the route, it returns a road
+  /// position at the end of the route. For looped routes, the projection takes potential repetitions
+  /// into account.
   ///
-  /// @param inert_pos Waypoint to add
-  /// @return created route defined by a series of waypoints
-  virtual IRoute& AddWaypoint(Vec3<units::length::meter_t>&& inert_pos) = 0;
+  /// @param longitudinal_offset Provided longitudinal offset
+  /// @param lateral_offset Provided lateral offset
+  /// @return Road position at provided offsets along the route reference line
+  [[nodiscard]] virtual OpenDriveRoadPosition ProjectAlongReferenceLine(units::length::meter_t longitudinal_offset, units::length::meter_t lateral_offset) const = 0;
 
-  /// Returns inertial position from track position
+  /// Return the longitudinal offset from its start to the given position along the route reference line.
+  /// The returned offset is always less or equal the length of the route.
+  /// Returns a std::nullopt if the provided position could not be mapped onto any road of the route.
   ///
-  /// @param route_pos    s coordinate on lane
-  /// @param lane_id      ID of lane
-  /// @param lane_offset  t coordinate on lane
-  /// @return position in Cartesian coordinate system
-  [[nodiscard]] virtual Vec3<units::length::meter_t> GetInertPos(units::length::meter_t route_pos,
-                                                                 LaneId lane_id,
-                                                                 units::length::meter_t lane_offset = units::length::meter_t{
-                                                                     0.0}) const = 0;
+  /// @param position End position
+  /// @return The longitudinal offset from start to the provided position, if position is valid
+  [[nodiscard]] virtual std::optional<units::length::meter_t> GetOffsetAlongReferenceLine(const Position &position) const = 0;
 
-  /// Returns interpolated value for the width of the lane at the given position
-  ///
-  /// @param lane_id    ID of lane to search in
-  /// @param route_pos  s coordinate of search start
-  /// @return width at position
-  [[nodiscard]] virtual units::length::meter_t GetLaneWidth(units::length::meter_t route_pos, LaneId lane_id) const = 0;
-
-  /// Returns ID of the lane that encloses the passed in position within its shape
-  ///
-  /// @param inert_pos  Position to search for the Lane ID
-  /// @return ID of the lane
-  [[nodiscard]] virtual LaneId GetLaneId(const Vec3<units::length::meter_t>& inert_pos) const = 0;
-
-  /// Returns distance from start to the given position along the set route
-  ///
-  /// @param inert_pos End position
-  /// @return distance from start to the given position
-  [[nodiscard]] virtual units::length::meter_t GetDistanceFromStartTo(const Vec3<units::length::meter_t>& inert_pos) const = 0;
-
-  /// Returns the length of the route
+  /// Return the length of the route.
+  /// If the route is looped the length of only one loop shall be returned.
   ///
   /// @return length of the route
   [[nodiscard]] virtual units::length::meter_t GetLength() const = 0;
diff --git a/include/MantleAPI/Map/i_route_repository.h b/include/MantleAPI/Map/i_route_repository.h
new file mode 100644
index 0000000000000000000000000000000000000000..521a5fc449fc6a544762308aa7b37817feacfa43
--- /dev/null
+++ b/include/MantleAPI/Map/i_route_repository.h
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+//-----------------------------------------------------------------------------
+/** @file  i_route_repository.h */
+//-----------------------------------------------------------------------------
+
+#ifndef MANTLEAPI_TRAFFIC_I_ROUTE_REPOSITORY
+#define MANTLEAPI_TRAFFIC_I_ROUTE_REPOSITORY
+
+#include <MantleAPI/Map/i_route.h>
+#include <MantleAPI/Map/routing_definition.h>
+
+#include <memory>
+#include <string>
+
+namespace mantle_api
+{
+
+/// This interface provides CRUD functionality for routes.
+class IRouteRepository
+{
+public:
+  virtual ~IRouteRepository() = default;
+  /// Create a new route.
+  ///
+  /// @param name Name of the route
+  /// @param definition Routing definition used for building the route
+  /// @return A newly created route
+  virtual std::weak_ptr<IRoute> Create(const std::string& name, const RoutingDefinition& definition) = 0;
+
+  /// Get the route by the given name. 
+  /// Returns an unassigned pointer if no such route exists.
+  ///
+  /// @param name The name of the route
+  /// @return Route according to the given name (may be ambiguous)
+  [[nodiscard]] virtual std::weak_ptr<const IRoute> Get(const std::string& name) const = 0;
+
+  /// Get the route by the given unique ID. 
+  /// Returns an unassigned pointer if no such route exists.
+  ///
+  /// @param route_id Unique ID of the route
+  /// @return Route according to the given unique ID
+  [[nodiscard]] virtual std::weak_ptr<const IRoute> Get(UniqueId route_id) const = 0;
+
+  /// Check whether the repository contains a route with the given ID.
+  ///
+  /// @param route_id Unique ID to be searched for
+  /// @return true, if route with given ID exists, otherwise false
+  [[nodiscard]] virtual bool Contains(UniqueId route_id) const = 0;
+
+  /// Delete the route with the given unique ID.
+  ///
+  /// @param route_id The ID of the route to be deleted
+  virtual void Delete(UniqueId route_id) = 0;
+
+  /// Delete the route with the given name.
+  ///
+  /// @param name The name of the route to be deleted
+  virtual void Delete(const std::string& name) = 0;
+
+  /// Reset the route repository.
+  ///
+  /// Establishes a defined initial state, such as removing all routes
+  virtual void Reset() = 0;
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_TRAFFIC_I_ROUTE_REPOSITORY
diff --git a/include/MantleAPI/Map/lane_definition.h b/include/MantleAPI/Map/lane_definition.h
index 13d278a5b2c2060ceee2c77616839a9a94e70474..e72d205d9fa7ae543a55708961030c886901e1f6 100644
--- a/include/MantleAPI/Map/lane_definition.h
+++ b/include/MantleAPI/Map/lane_definition.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2022, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -24,7 +25,7 @@ namespace mantle_api
 /// A LaneId does not necessarily have to be unique.
 /// Depending on the scenario description it can repeat,
 /// as e.g. for every uniqulely identifiable road (i.e. OpenDRIVE).
-using LaneId = int64_t;
+using LaneId = std::int64_t;
 
 }  // namespace mantle_api
 
diff --git a/include/MantleAPI/Map/map_details.h b/include/MantleAPI/Map/map_details.h
index 8e9895be2bce18f6c5dbce11607562ee40d7c623..a08ec417ae237f6b10477b1c8c3f09004a019119 100644
--- a/include/MantleAPI/Map/map_details.h
+++ b/include/MantleAPI/Map/map_details.h
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2021-2024, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2021-2025, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -17,6 +17,7 @@
 
 #include <MantleAPI/Common/position.h>
 
+#include <cstdint>
 #include <memory>
 #include <vector>
 
@@ -24,11 +25,11 @@ namespace mantle_api
 {
 
 /// Specify the interpretation of the vector of points in the map region.
-enum class MapRegionType
+enum class MapRegionType : std::uint8_t
 {
-  kUndefined = 0,   ///< Undefined interpretation of the vector of points in the map region.
-  kRoute,   ///< Route interpretation of the vector of points in the map region.
-  kPolygon   ///< Polygon interpretation of the vector of points in the map region.
+  kUndefined = 0,  ///< Undefined interpretation of the vector of points in the map region.
+  kRoute,          ///< Route interpretation of the vector of points in the map region.
+  kPolygon         ///< Polygon interpretation of the vector of points in the map region.
 };
 
 /// Definition of the map area
@@ -43,11 +44,8 @@ struct MapDetails
     return std::make_unique<MapDetails>(*this);
   }
 
-  /// Area of the map (e.g. GPS latitude, GPS longitude)
-  std::vector<Position> map_region;
-
-  /// Type of map region.
-  MapRegionType map_region_type;
+  std::vector<Position> map_region;  ///< Area of the map (e.g. GPS latitude, GPS longitude)
+  MapRegionType map_region_type;     ///< Type of map region.
 };
 
 }  // namespace mantle_api
diff --git a/include/MantleAPI/Map/routing_definition.h b/include/MantleAPI/Map/routing_definition.h
new file mode 100644
index 0000000000000000000000000000000000000000..feb9ac4cfb3d48568fd183a5802dea79ba013eb9
--- /dev/null
+++ b/include/MantleAPI/Map/routing_definition.h
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2022-2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+//-----------------------------------------------------------------------------
+/// @file routing_definition.h
+//-----------------------------------------------------------------------------
+
+#ifndef MANTLEAPI_MAP_ROUTING_DEFINITION_H
+#define MANTLEAPI_MAP_ROUTING_DEFINITION_H
+
+#include <MantleAPI/Common/vector.h>
+#include <units.h>
+
+#include <cstdint>
+#include <tuple>
+#include <vector>
+
+#include "MantleAPI/Common/position.h"
+
+namespace mantle_api
+{
+
+/// Define how the route from a waypoint forward should be calculated.
+enum class RoutingStrategy : std::uint8_t
+{
+  kUnknown = 0,         ///< Invalid initialization value
+  kUndefined,           ///< Use the default route of the simulator
+  kFastest,             ///< Use fastest path routing
+  kLeastIntersections,  ///< Use least intersection routing
+  kShortest             ///< Use shortest path routing
+};
+
+/// Group a Waypoint with a RoutingStrategy.
+struct RoutingWaypoint
+{
+  Position position;                 ///< Position defined for the routing waypoint
+  RoutingStrategy routing_strategy;  ///< Routing strategy defined for the routing waypoint
+};
+
+/// A raw set of positions and routing strategy for
+/// linking them, from which the actual route can be calculated
+struct RoutingDefinition
+{
+  std::vector<RoutingWaypoint> routing_waypoints;  ///< The list of waypoints with associated RoutingStrategies
+  bool is_looped = false;                          ///< Flag indicating whether the resulting route shall be looped
+};
+
+/// Equality comparison for RoutingWaypoint.
+///
+/// @param[in] lhs The left-hand side value for the comparison
+/// @param[in] rhs The right-hand side value for the comparison
+/// @returns true if the values of lhs and rhs are equal
+constexpr bool operator==(const RoutingWaypoint& lhs, const RoutingWaypoint& rhs) noexcept
+{
+  return std::tie(lhs.position, lhs.routing_strategy) == std::tie(rhs.position, rhs.routing_strategy);
+}
+
+/// Inequality comparison for RoutingWaypoint.
+///
+/// @param[in] lhs The left-hand side value for the comparison
+/// @param[in] rhs The right-hand side value for the comparison
+/// @returns true if the values of lhs and rhs are not equal
+constexpr bool operator!=(const RoutingWaypoint& lhs, const RoutingWaypoint& rhs) noexcept
+{
+  return !(lhs == rhs);
+}
+
+/// Equality comparison for RoutingDefinition.
+///
+/// @param[in] lhs The left-hand side value for the comparison
+/// @param[in] rhs The right-hand side value for the comparison
+/// @returns true if the values of lhs and rhs are equal
+inline bool operator==(const RoutingDefinition& lhs, const RoutingDefinition& rhs) noexcept
+{
+  return std::tie(lhs.routing_waypoints, lhs.is_looped) == std::tie(rhs.routing_waypoints, rhs.is_looped);
+}
+
+/// Inequality comparison for RoutingDefinition.
+///
+/// @param[in] lhs The left-hand side value for the comparison
+/// @param[in] rhs The right-hand side value for the comparison
+/// @returns true if the values of lhs and rhs are not equal
+inline bool operator!=(const RoutingDefinition& lhs, const RoutingDefinition& rhs) noexcept
+{
+  return !(lhs == rhs);
+}
+
+
+/// Output stream operator for RoutingWaypoint.
+///
+/// @param[in] os The output stream
+/// @param[in] waypoint The RoutingWaypoint to be printed
+/// @returns The output stream with the printed RoutingWaypoint
+///
+inline std::ostream& operator<<(std::ostream& os, const RoutingWaypoint& waypoint)
+{
+  os << "RoutingWaypoint(.position=" << waypoint.position << ", .routing_strategy=" << static_cast<int>(waypoint.routing_strategy) << ')';
+  return os;
+}
+
+/// Output stream operator for RoutingDefinition.
+///
+/// @param[in] os The output stream
+/// @param[in] routing_definition The RoutingDefinition to be printed
+/// @returns The output stream with the printed RoutingDefinition
+///
+inline std::ostream& operator<<(std::ostream& os, const RoutingDefinition& routing_definition)
+{
+  os << "RoutingDefinition(";
+  for (auto idx = 0U; idx < routing_definition.routing_waypoints.size(); ++idx)
+  {
+    os << (idx == 0U ? "[" : ", [") << std::to_string(idx) << "]=" << routing_definition.routing_waypoints.at(idx);
+  }
+  os << ')';
+  return os;
+}
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_COMMON_ROUTING_DEFINITION_H
diff --git a/include/MantleAPI/Traffic/control_strategy.h b/include/MantleAPI/Traffic/control_strategy.h
index bbd59dab7b53b9f236631e2a41a89b144d6c30ef..a3a3fc5e31ccae5574a2172e62e5112a2bb83b7e 100644
--- a/include/MantleAPI/Traffic/control_strategy.h
+++ b/include/MantleAPI/Traffic/control_strategy.h
@@ -1,6 +1,7 @@
 /*******************************************************************************
  * Copyright (c) 2021-2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
  * Copyright (c) 2022-2025 Ansys, Inc.
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -24,6 +25,8 @@
 #include <MantleAPI/Traffic/traffic_light_properties.h>
 #include <MantleAPI/Traffic/vehicle_light_properties.h>
 
+#include <cstdint>
+#include <optional>
 #include <utility>  // std::move
 #include <vector>
 
@@ -31,29 +34,29 @@ namespace mantle_api
 {
 
 /// Movement domain of the control strategy, which specifies the desired movement behavior for the entity
-enum class MovementDomain
+enum class MovementDomain : std::uint8_t
 {
-  kUndefined = 0,
-  kLateral,
-  kLongitudinal,
-  kBoth,
-  kNone
+  kUndefined = 0,  ///< The movement domain is undefined.
+  kLateral,        ///< The movement domain is lateral.
+  kLongitudinal,   ///< The movement domain is longitudinal.
+  kBoth,           ///< The movement domain is both lateral and longitudinal.
+  kNone            ///< The movement domain is none.
 };
 
 /// Type of the control strategy
-enum class ControlStrategyType
+enum class ControlStrategyType : std::uint8_t
 {
-  kUndefined = 0,
-  kKeepVelocity,
-  kKeepLaneOffset,
-  kFollowHeadingSpline,
-  kFollowLateralOffsetSpline,
-  kFollowVelocitySpline,
-  kAcquireLaneOffset,
-  kFollowTrajectory,
-  kUpdateTrafficLightStates,
-  kPerformLaneChange,
-  kUpdateVehicleLightStates,
+  kUndefined = 0,              ///< The control strategy type is undefined.
+  kKeepVelocity,               ///< The control strategy type is to keep the current velocity.
+  kKeepLaneOffset,             ///< The control strategy type is to keep the current lane offset.
+  kFollowHeadingSpline,        ///< The control strategy type is to follow a heading angle from spline.
+  kFollowLateralOffsetSpline,  ///< The control strategy type is to follow a lateral offset from spline.
+  kFollowVelocitySpline,       ///< The control strategy type is to follow a velocity from spline.
+  kAcquireLaneOffset,          ///< The control strategy type is to acquire a lane offset.
+  kFollowTrajectory,           ///< The control strategy type is to follow a trajectory.
+  kUpdateTrafficLightStates,   ///< The control strategy type is to update traffic light states.
+  kPerformLaneChange,          ///< The control strategy type is to perform a lane change.
+  kUpdateVehicleLightStates,   ///< The control strategy type is to update the vehicle light states.
 };
 
 /// Defintion of all control strategies for a single entity.
@@ -102,6 +105,7 @@ struct KeepVelocityControlStrategy : public ControlStrategy
   /// @brief Constructs a KeepVelocityControlStrategy as a ControlStrategy with predefined values
   KeepVelocityControlStrategy()
       : ControlStrategy{MovementDomain::kLongitudinal, ControlStrategyType::kKeepVelocity} {}
+
   // Doesn't need configuration attributes. Controller keeps current velocity on adding entity or update
 };
 
@@ -111,6 +115,7 @@ struct KeepLaneOffsetControlStrategy : public ControlStrategy
   /// @brief Constructs a KeepLaneOffsetControlStrategy as a ControlStrategy with predefined values
   KeepLaneOffsetControlStrategy()
       : ControlStrategy{MovementDomain::kLateral, ControlStrategyType::kKeepLaneOffset} {}
+
   // Doesn't need configuration attributes. Controller keeps current lane offset on adding entity or update
 };
 
@@ -195,22 +200,22 @@ struct FollowLateralOffsetSplineControlStrategy : public ControlStrategy
 };
 
 /// Defines how a target value will be acquired (with a constant rate, in a defined distance, within a defined time).
-enum class Dimension
+enum class Dimension : std::uint8_t
 {
-  kUndefined = 0,
-  kDistance,
-  kRate,
-  kTime
+  kUndefined = 0,  ///< The dimension of the transition function is undefined.
+  kDistance,       ///< The target value will be acquired within a defined distance.
+  kRate,           ///< The target value will be acquired with a constant rate.
+  kTime            ///< The target value will be acquired within a defined time.
 };
 
 /// Function type used to represent the change of a given variable over time or distance.
-enum class Shape
+enum class Shape : std::uint8_t
 {
-  kUndefined = 0,
-  kStep,
-  kCubic,
-  kLinear,
-  kSinusoidal
+  kUndefined = 0,  ///< The shape of the transition function is undefined.
+  kStep,           ///< The transition function is a step function.
+  kCubic,          ///< The transition function is a cubic function.
+  kLinear,         ///< The transition function is a linear function.
+  kSinusoidal      ///< The transition function is a sinusoidal function.
 };
 
 /// Specifies the dynamics of a value transition and defines how the value changes over time or distance.
@@ -248,9 +253,12 @@ struct AcquireLaneOffsetControlStrategy : public ControlStrategy
         continuous{continuous},
         lane_offset_action_dynamics{lane_offset_action_dynamics} {}
 
-  units::length::meter_t offset;                         ///< Lane offset
-  bool continuous;                                       ///< If false, the action ends when the target lane-offset is reached. If true it does not end but has to be stopped.
-  LaneOffsetActionDynamics lane_offset_action_dynamics;  ///< Parameters defining the dynamics of the LaneOffsetAction
+  /// Lane offset
+  units::length::meter_t offset;
+  /// If false, the action ends when the target lane-offset is reached. If true it does not end but has to be stopped.
+  bool continuous;
+  /// Parameters defining the dynamics of the LaneOffsetAction
+  LaneOffsetActionDynamics lane_offset_action_dynamics;
 };
 
 /// Controls the transition of a vehicle light state to the target light state
@@ -286,8 +294,8 @@ struct TrafficLightStateControlStrategy : public ControlStrategy
   bool repeat_states;
 };
 
-/// Definition of time value context as either absolute or relative
-enum class ReferenceContext
+/// Definition of time value context as either absolute or relative.
+enum class ReferenceContext : std::uint8_t
 {
   kAbsolute = 0,
   kRelative
diff --git a/include/MantleAPI/Traffic/default_routing_behavior.h b/include/MantleAPI/Traffic/default_routing_behavior.h
index 215a845491c9de4f9e2123a283b685ee1a93b1fb..e5e86fe657afa191ccd9f2143edb8f6003893161 100644
--- a/include/MantleAPI/Traffic/default_routing_behavior.h
+++ b/include/MantleAPI/Traffic/default_routing_behavior.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2022, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -15,14 +16,16 @@
 #ifndef MANTLEAPI_TRAFFIC_DEFAULT_ROUTING_BEHAVIOR_H
 #define MANTLEAPI_TRAFFIC_DEFAULT_ROUTING_BEHAVIOR_H
 
+#include <cstdint>
+
 /// MantleAPI namespace
 namespace mantle_api
 {
 
-/// Specify behavior to end of route
-enum class DefaultRoutingBehavior
+/// Specify behavior to end of route.
+enum class DefaultRoutingBehavior : std::uint8_t
 {
-  kStop,        ///< Do nothing
+  kStop = 0,    ///< Do nothing
   kRandomRoute  ///< Randomly select where to go next
 };
 
diff --git a/include/MantleAPI/Traffic/entity_properties.h b/include/MantleAPI/Traffic/entity_properties.h
index ff44e4a3daa67814feffac621eac37aa69c59a09..92dea5163d2ec0addafbf3a85ee365d93792bd9e 100644
--- a/include/MantleAPI/Traffic/entity_properties.h
+++ b/include/MantleAPI/Traffic/entity_properties.h
@@ -1,6 +1,7 @@
 /*******************************************************************************
  * Copyright (c) 2021-2025, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
  * Copyright (c) 2022 Ansys, Inc.
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -19,264 +20,437 @@
 #include <MantleAPI/Common/bounding_box.h>
 #include <MantleAPI/Common/floating_point_helper.h>
 #include <MantleAPI/Common/spline.h>
+#include <MantleAPI/Common/unit_definitions.h>
 #include <MantleAPI/Common/vector.h>
+#include <units.h>
 
-#include <limits>
+#include <cstdint>
 #include <map>
 #include <string>
+#include <utility>
 
 namespace mantle_api
 {
 
 /// Specify the type of an entity.
-enum class EntityType
+enum class EntityType : std::uint8_t
 {
-  // Other (unspecified but known)
-  kOther = 1,
-  // Object is a vehicle.
-  kVehicle = 2,
-  // Object is a pedestrian.
-  kPedestrian = 3,
-  // Object is an animal.
-  kAnimal = 4,
-  // Object is static and does not move
-  kStatic = 5
+  kUnknown = 0,  ///< The type of the entity is unknown.
+  kOther,        ///< The type of the entity is known, but unspecified.
+  kVehicle,      ///< The entity is a vehicle.
+  kPedestrian,   ///< The entity is a pedestrian.
+  kAnimal,       ///< The entity is an animal.
+  kStatic        ///< The entity is static and does not move.
 };
 
 /// Basic properties that describe scenario entities.
 struct EntityProperties
 {
-  /// @brief Constructs EntityProperties from its members
+  /// Destructor
+  virtual ~EntityProperties() = default;
+
+  BoundingBox bounding_box{};                     ///< The three dimensional bounding box that encloses the entity.
+  EntityType type{};                              ///< Type of the entity object (e.g. vehicle, pedestrian).
+  std::string model;                              ///< Definition of the model of the entity.
+  std::map<std::string, std::string> properties;  ///< Additional properties as name value pairs.
+  units::mass::kilogram_t mass{};                 ///< The mass of the entity in kg.
+
+protected:
+  /// Default constructor
+  ///
+  /// @param[in] type Type of the entity object (e.g. vehicle, pedestrian)
+  explicit EntityProperties(EntityType type) noexcept
+      : type{type} {}
+
+  /// Construct EntityProperties from its members
   ///
   /// @param[in] bounding_box The three dimensional bounding box that encloses the entity
-  /// @param[in] type         Type of the entity object (e.g. vehicle, pedestrian)
-  /// @param[in] model        Definition of the model of the entity
-  /// @param[in] properties   Additional properties as name value pairs
-  /// @param[in] mass         The mass of the entity in kg
-  explicit EntityProperties(BoundingBox bounding_box = {},
-                            EntityType type = EntityType::kOther,
-                            std::string model = {},
-                            std::map<std::string, std::string> properties = {},
-                            units::mass::kilogram_t mass = {})
+  /// @param[in] type Type of the entity object (e.g. vehicle, pedestrian)
+  /// @param[in] model Definition of the model of the entity
+  /// @param[in] properties Additional properties as name value pairs
+  /// @param[in] mass The mass of the entity in kg
+  explicit EntityProperties(BoundingBox bounding_box,
+                            EntityType type,
+                            std::string model,
+                            std::map<std::string, std::string> properties,
+                            units::mass::kilogram_t mass) noexcept
       : bounding_box{bounding_box},
         type{type},
         model{std::move(model)},
         properties{std::move(properties)},
         mass{mass} {}
 
-  virtual ~EntityProperties() = default;
+  /// Copy constructor
+  /// @param[in] other The object to copy from
+  EntityProperties(const EntityProperties& other) = default;
+
+  /// Copy assignment operator
+  /// @param[in] other The object to copy from
+  /// @returns A reference to this object
+  EntityProperties& operator=(const EntityProperties& other) noexcept = default;
 
-  /// The three dimensional bounding box that encloses the entity
-  BoundingBox bounding_box;
-  /// Type of the entity object (e.g. vehicle, pedestrian)
-  EntityType type;
-  /// Definition of the model of the entity
-  std::string model;
-  /// Additional properties as name value pairs
-  std::map<std::string, std::string> properties;
-  /// The mass of the entity in kg
-  units::mass::kilogram_t mass;
+  /// Move constructor
+  /// @param[in] other The object to move from
+  EntityProperties(EntityProperties&& other) noexcept = default;
+
+  /// Move assignment operator
+  /// @param[in] other The object to move from
+  /// @returns A reference to this object
+  EntityProperties& operator=(EntityProperties&& other) noexcept = default;
 };
 
-/// @brief Equality comparison for EntityProperties.
+/// Equality comparison for EntityProperties.
 ///
-/// @param[in]  lhs The left-hand side value for the comparison
-/// @param[in]	rhs The right-hand side value for the comparison
-/// @returns  true if the values of lhs exactly equal to the values of rhs.
+/// @param[in] lhs The left-hand side value for the comparison.
+/// @param[in] rhs The right-hand side value for the comparison.
+/// @returns true if the values of lhs exactly equal to the values of rhs.
 constexpr bool operator==(const EntityProperties& lhs, const EntityProperties& rhs) noexcept
 {
-  return lhs.bounding_box == rhs.bounding_box && lhs.type == rhs.type && lhs.model == rhs.model;
+  return std::tie(lhs.bounding_box, lhs.type, lhs.model, lhs.properties, lhs.mass) ==
+         std::tie(rhs.bounding_box, rhs.type, rhs.model, rhs.properties, rhs.mass);
+}
+
+/// Inequality comparison for EntityProperties.
+///
+/// @param[in] lhs The left-hand side value for the comparison.
+/// @param[in] rhs The right-hand side value for the comparison.
+/// @returns true if the values of lhs do not exactly equal to the values of rhs.
+constexpr bool operator!=(const EntityProperties& lhs, const EntityProperties& rhs) noexcept
+{
+  return !(lhs == rhs);
 }
 
 /// Specify the class of a vehicle.
-enum class VehicleClass
+enum class VehicleClass : std::uint8_t
 {
-  kOther = 1,  // Other (unspecified but known) type of vehicle.
-  // Vehicle is a small car.
-  // Definition: Hatchback car with maximum length 4 m.
-  kSmall_car = 2,
-  // Vehicle is a compact car.
-  // Definition: Hatchback car with length between 4 and 4.5 m.
-  kCompact_car = 3,
-  // Vehicle is a medium car.
-  // Definition: Hatchback or sedan with length between 4.5 and 5 m.
-  kMedium_car = 4,
-  // Vehicle is a luxury car.
-  // Definition: Sedan or coupe that is longer then 5 m.
-  kLuxury_car = 5,
-  // Vehicle is a delivery van.
-  // Definition: A delivery van.
-  kDelivery_van = 6,
-  // Vehicle is a heavy truck.
-  kHeavy_truck = 7,
-  // Vehicle is a truck with semitrailer.
-  kSemitrailer = 8,
-  // Vehicle is a trailer (possibly attached to another vehicle).
-  kTrailer = 9,
-  // Vehicle is a motorbike or moped.
-  kMotorbike = 10,
-  // Vehicle is a bicycle (without motor and specific lights).
-  kBicycle = 11,
-  // Vehicle is a bus.
-  kBus = 12,
-  // Vehicle is a tram.
-  kTram = 13,
-  // Vehicle is a train.
-  kTrain = 14,
-  // Vehicle is a wheelchair.
-  kWheelchair = 15,
-  // Vehicle type not specified properly.
-  kInvalid = -1
+  kUnknown = 0,    ///< The type of the vehicle is unknown.
+  kOther,          ///< The type of the vehicle is known, but unspecified.
+  kSmallCar,       ///< The vehicle is a small car. Definition: Hatchback car with maximum length 4 m.
+  kCompactCar,     ///< The vehicle is a compact car. Definition: Hatchback car with length between 4 and 4.5 m.
+  kMediumCar,      ///< The vehicle is a medium car. Definition: Hatchback or sedan with length between 4.5 and 5 m.
+  kLuxuryCar,      ///< The vehicle is a luxury car. Definition: Sedan or coupe that is longer then 5 m.
+  kDeliveryVan,    ///< The vehicle is a delivery van.
+  kHeavyTruck,     ///< The vehicle is a heavy truck.
+  kSemiTrailer,    ///< The vehicle is a truck with semi-trailer.
+  kTrailer,        ///< The vehicle is a trailer. The trailer may be attached to another vehicle.
+  kMotorcycle,     ///< The vehicle is a motorcycle or moped.
+  kBicycle,        ///< The vehicle is a bicycle (without motor and specific lights).
+  kBus,            ///< The vehicle is a bus.
+  kTram,           ///< The vehicle is a tram.
+  kTrain,          ///< The vehicle is a train.
+  kWheelchair,     ///< The vehicle is a wheelchair.
+  kStandupScooter  ///< The vehicle is a stand-up scooter.
 };
 
 /// This struct represents the performance properties of the vehicle
 struct Performance
 {
-  /// Maximum speed of the vehicle
-  units::velocity::meters_per_second_t max_speed{std::numeric_limits<double>::infinity()};
-  /// Maximum acceleration of the vehicle
-  units::acceleration::meters_per_second_squared_t max_acceleration{std::numeric_limits<double>::infinity()};
-  /// Maximum deceleration of the vehicle
-  units::acceleration::meters_per_second_squared_t max_deceleration{std::numeric_limits<double>::infinity()};
-  /// Maximum acceleration rate of the vehicle. If omitted then infinity is assumed
-  units::jerk::meters_per_second_cubed_t max_acceleration_rate{std::numeric_limits<double>::infinity()};
-  /// Maximum deceleration rate of the vehicle. If omitted then infinity is assumed
-  units::jerk::meters_per_second_cubed_t max_deceleration_rate{std::numeric_limits<double>::infinity()};
+  units::velocity::meters_per_second_t max_speed;                     ///< Maximum speed of the vehicle
+  units::acceleration::meters_per_second_squared_t max_acceleration;  ///< Maximum acceleration of the vehicle
+  units::acceleration::meters_per_second_squared_t max_deceleration;  ///< Maximum deceleration of the vehicle
+  units::jerk::meters_per_second_cubed_t max_acceleration_rate;       ///< Maximum acceleration rate of the vehicle. If omitted, infinity is assumed.
+  units::jerk::meters_per_second_cubed_t max_deceleration_rate;       ///< Maximum deceleration rate of the vehicle. If omitted, infinity is assumed.
 };
 
-/// @brief Equality comparison for Performance.
+/// Equality comparison for Performance.
 ///
-/// @param[in]  lhs The left-hand side value for the comparison
-/// @param[in]	rhs The right-hand side value for the comparison
-/// @returns  true if the values of lhs almost equal to the values of rhs.
+/// @param[in] lhs The left-hand side value for the comparison.
+/// @param[in] rhs The right-hand side value for the comparison.
+/// @returns true if the values of lhs almost equal to the values of rhs.
 constexpr bool operator==(const Performance& lhs, const Performance& rhs) noexcept
 {
-  return AlmostEqual(lhs.max_speed, rhs.max_speed) &&
-         AlmostEqual(lhs.max_acceleration, rhs.max_acceleration) &&
-         AlmostEqual(lhs.max_deceleration, rhs.max_deceleration) &&
-         AlmostEqual(lhs.max_acceleration_rate, rhs.max_acceleration_rate) &&
-         AlmostEqual(lhs.max_deceleration_rate, rhs.max_deceleration_rate);
+  return AlmostEqual(std::tie(lhs.max_speed, lhs.max_acceleration, lhs.max_deceleration, lhs.max_acceleration_rate, lhs.max_deceleration_rate),
+                     std::tie(rhs.max_speed, rhs.max_acceleration, rhs.max_deceleration, rhs.max_acceleration_rate, rhs.max_deceleration_rate));
+}
+
+/// Inequality comparison for Performance.
+///
+/// @param[in] lhs The left-hand side value for the comparison.
+/// @param[in] rhs The right-hand side value for the comparison.
+/// @returns true if the values of lhs do not exactly equal to the values of rhs.
+constexpr bool operator!=(const Performance& lhs, const Performance& rhs) noexcept
+{
+  return !(lhs == rhs);
 }
 
-/// This struct represents the definition of vehicle axle
+/// Definition of a vehicle axle.
 struct Axle
 {
-  /// Maximum steering angle which can be performed by the wheels on this axle
-  units::angle::radian_t max_steering{0.0};
-  /// Diameter of the wheels on this axle
-  units::length::meter_t wheel_diameter{0.0};
-  /// Distance of the wheels center lines at zero steering
-  units::length::meter_t track_width{0.0};
-  /// Position of the axle with respect to the center of vehicles bounding box
-  Vec3<units::length::meter_t> bb_center_to_axle_center{};
+  units::angle::radian_t max_steering;                    ///< Maximum steering angle which can be performed by the wheels on this axle.
+  units::length::meter_t wheel_diameter;                  ///< Diameter of the wheels on this axle.
+  units::length::meter_t track_width;                     ///< Distance of the wheels center lines at zero steering.
+  Vec3<units::length::meter_t> bb_center_to_axle_center;  ///< Position of the axle with respect to the center of vehicles bounding box.
 };
 
-/// @brief Equality comparison for Axle.
+/// Equality comparison for Axle.
 ///
-/// @param[in]  lhs The left-hand side value for the comparison
-/// @param[in]	rhs The right-hand side value for the comparison
-/// @returns  true if the values of lhs (almost) equal to the values of rhs.
+/// @param[in] lhs The left-hand side value for the comparison.
+/// @param[in] rhs The right-hand side value for the comparison.
+/// @returns true if the values of lhs (almost) equal to the values of rhs.
 constexpr bool operator==(const Axle& lhs, const Axle& rhs) noexcept
 {
-  return AlmostEqual(lhs.max_steering, rhs.max_steering) &&
-         AlmostEqual(lhs.wheel_diameter, rhs.wheel_diameter) &&
-         AlmostEqual(lhs.track_width, rhs.track_width) &&
+  return AlmostEqual(std::tie(lhs.max_steering, lhs.wheel_diameter, lhs.track_width),
+                     std::tie(rhs.max_steering, rhs.wheel_diameter, rhs.track_width)) &&
          lhs.bb_center_to_axle_center == rhs.bb_center_to_axle_center;
 }
 
+/// Inequality comparison for Axle.
+///
+/// @param[in] lhs The left-hand side value for the comparison.
+/// @param[in] rhs The right-hand side value for the comparison.
+/// @returns true if the values of lhs do not exactly equal to the values of rhs.
+constexpr bool operator!=(const Axle& lhs, const Axle& rhs) noexcept
+{
+  return !(lhs == rhs);
+}
+
 /// Additional properties for entity objects of type vehicle
 struct VehicleProperties : public EntityProperties
 {
-  /// Category of the vehicle (bicycle, train,...)
-  VehicleClass classification{VehicleClass::kOther};
+  /// Default constructor
+  VehicleProperties() noexcept
+      : EntityProperties{EntityType::kVehicle} {};
+
+  /// Construct VehicleProperties from its members
+  ///
+  /// @param[in] bounding_box The three dimensional bounding box that encloses the entity
+  /// @param[in] model Definition of the model of the entity
+  /// @param[in] properties Additional properties as name value pairs
+  /// @param[in] mass The mass of the entity in kg
+  /// @param[in] classification Class of the vehicle
+  /// @param[in] performance Performance properties of the vehicle
+  /// @param[in] front_axle Front axle of the vehicle
+  /// @param[in] rear_axle Rear axle of the vehicle
+  /// @param[in] is_host Determines, if the vehicle is host or not
+  /// @param[in] is_controlled_externally Determines, if the vehicle is controlled externally or not
+  explicit VehicleProperties(BoundingBox bounding_box,
+                             std::string model,
+                             std::map<std::string, std::string> properties,
+                             units::mass::kilogram_t mass,
+                             VehicleClass classification,
+                             Performance performance,
+                             Axle front_axle,
+                             Axle rear_axle,
+                             bool is_host,
+                             bool is_controlled_externally) noexcept
+      : EntityProperties{bounding_box, EntityType::kVehicle, std::move(model), std::move(properties), mass}, classification{classification}, performance{performance}, front_axle{front_axle}, rear_axle{rear_axle}, is_host{is_host}, is_controlled_externally{is_controlled_externally} {}
+
+  /// Destructor
+  ~VehicleProperties() noexcept override = default;
+
+  /// Copy constructor
+  /// @param[in] other The object to copy from
+  VehicleProperties(const VehicleProperties& other) = default;
 
-  /// Performance properties of the vehicle
-  Performance performance{};
+  /// Copy assignment operator
+  /// @param[in] other The object to copy from
+  /// @returns A reference to this object
+  VehicleProperties& operator=(const VehicleProperties& other) noexcept = default;
 
-  /// Front axle of the vehicle
-  Axle front_axle{};
-  /// Rear axle of the vehicle
-  Axle rear_axle{};
+  /// Move constructor
+  /// @param[in] other The object to move from
+  VehicleProperties(VehicleProperties&& other) noexcept = default;
+
+  /// Move assignment operator
+  /// @param[in] other The object to move from
+  /// @returns A reference to this object
+  VehicleProperties& operator=(VehicleProperties&& other) noexcept = default;
+
+  VehicleClass classification{};  ///< Class of the vehicle
+  Performance performance{};      ///< Performance properties of the vehicle
+  Axle front_axle{};              ///< Front axle of the vehicle
+  Axle rear_axle{};               ///< Rear axle of the vehicle
+  bool is_host{};                 ///< Determines, if the vehicle is host or not
 
-  /// The "is_host" flag determines, if the vehicle is host or not
-  bool is_host{false};
   // TODO: remove, once external control for traffic is implemented through controllers
-  /// The "is_controlled_externally" flag determines, if the vehicle is controlled externally or not
-  bool is_controlled_externally{false};
+  bool is_controlled_externally{};  ///< Determines, if the vehicle is controlled externally or not
 };
 
-/// @brief Equality comparison for VehicleProperties.
+/// Equality comparison for VehicleProperties.
 ///
-/// @param[in]  lhs The left-hand side value for the comparison
-/// @param[in]	rhs The right-hand side value for the comparison
-/// @returns  true if the values of lhs exactly equal to the values of rhs.
+/// @param[in] lhs The left-hand side value for the comparison
+/// @param[in] rhs The right-hand side value for the comparison
+/// @returns true if the values of lhs exactly equal to the values of rhs.
 constexpr bool operator==(const VehicleProperties& lhs, const VehicleProperties& rhs) noexcept
 {
-  return lhs.bounding_box == rhs.bounding_box && lhs.type == rhs.type && lhs.model == rhs.model &&
-         lhs.classification == rhs.classification && lhs.performance == rhs.performance &&
-         lhs.front_axle == rhs.front_axle && lhs.rear_axle == rhs.rear_axle &&
-         lhs.is_host == rhs.is_host;
+  return std::tie(static_cast<const EntityProperties&>(lhs), lhs.classification, lhs.performance, lhs.front_axle, lhs.rear_axle, lhs.is_host, lhs.is_controlled_externally) ==
+         std::tie(static_cast<const EntityProperties&>(rhs), rhs.classification, rhs.performance, rhs.front_axle, rhs.rear_axle, rhs.is_host, rhs.is_controlled_externally);
+}
+
+/// Inequality comparison for VehicleProperties.
+///
+/// @param[in] lhs The left-hand side value for the comparison
+/// @param[in] rhs The right-hand side value for the comparison
+/// @returns true if the values of lhs do not exactly equal to the values of rhs.
+constexpr bool operator!=(const VehicleProperties& lhs, const VehicleProperties& rhs) noexcept
+{
+  return !(lhs == rhs);
 }
 
+/// Specify the class of a pedestrian.
 struct PedestrianProperties : public EntityProperties
 {
+  /// Default constructor
+  PedestrianProperties() noexcept
+      : EntityProperties{EntityType::kPedestrian} {};
+
+  /// Construct PedestrianProperties from its members
+  ///
+  /// @param[in] bounding_box The three dimensional bounding box that encloses the entity
+  /// @param[in] model Definition of the model of the entity
+  /// @param[in] properties Additional properties as name value pairs
+  /// @param[in] mass The mass of the entity in kg
+  explicit PedestrianProperties(BoundingBox bounding_box,
+                                std::string model,
+                                std::map<std::string, std::string> properties,
+                                units::mass::kilogram_t mass) noexcept
+      : EntityProperties{bounding_box, EntityType::kPedestrian, std::move(model), std::move(properties), mass} {}
+
+  /// Destructor
+  ~PedestrianProperties() noexcept override = default;
+
+  /// Copy constructor
+  /// @param[in] other The object to copy from
+  PedestrianProperties(const PedestrianProperties& other) = default;
+
+  /// Copy assignment operator
+  /// @param[in] other The object to copy from
+  /// @returns A reference to this object
+  PedestrianProperties& operator=(const PedestrianProperties& other) noexcept = default;
+
+  /// Move constructor
+  /// @param[in] other The object to move from
+  PedestrianProperties(PedestrianProperties&& other) noexcept = default;
+
+  /// Move assignment operator
+  /// @param[in] other The object to move from
+  /// @returns A reference to this object
+  PedestrianProperties& operator=(PedestrianProperties&& other) noexcept = default;
+
+  // TODO: Add pedestrian specific properties
 };
 
-/// Specifies the type of a static object.
-/// The values are derived from ASAM OSI stationary object type
-enum class StaticObjectType
+/// Equality comparison for PedestrianProperties.
+///
+/// @param[in] lhs The left-hand side value for the comparison
+/// @param[in] rhs The right-hand side value for the comparison
+/// @returns true if the values of lhs exactly equal to the values of rhs.
+constexpr bool operator==(const PedestrianProperties& lhs, const PedestrianProperties& rhs) noexcept
 {
-  kOther = 1,  // Other (unspecified but known) type of static object.
-  // Object is a bridge.
-  kBridge = 2,
-  // Object is a building.
-  kBuilding = 3,
-  // Object is a pole (e.g. from a traffic light).
-  kPole = 4,
-  // Object is a pylon.
-  kPylon = 5,
-  // Object is a delineator (e.g. at a construction site).
-  kDelineator = 6,
-  // Object is a tree.
-  kTree = 7,
-  // Object is a barrier.
-  kBarrier = 8,
-  // Object is vegetation.
-  kVegetation = 9,
-  // Object is a curbstone.
-  kCurbstone = 10,
-  // Object is a wall.
-  kWall = 11,
-  // Landmarks corresponding to vertical structures in the environment.
-  kVerticalStructure = 12,
-  // Landmarks corresponding to rectangular structures in the environment, like walls.
-  kRectangularStructure = 13,
-  // Landmarks corresponding to overhead structures in the environment, like sign bridges.
-  kOverheadStructure = 14,
-  // Landmarks corresponding to reflective structures in the environment, like reflective poles on the road boarder.
-  kReflectiveStructure = 15,
-  // Landmarks corresponding to construction site elements in the environment, like beacons.
-  kConstructionSiteElement = 16,
-  // Object is a speed bump.
-  kSpeedBump = 17,
-  // Landmarks corresponding to sources of electromagnetic waves in the environment, like street lights.
-  kEmittingStructure = 18,
-  // Static object type not specified properly.
-  kInvalid = -1
+  return static_cast<const EntityProperties&>(lhs) == static_cast<const EntityProperties&>(rhs);
+}
+
+/// Inequality comparison for PedestrianProperties.
+///
+/// @param[in] lhs The left-hand side value for the comparison
+/// @param[in] rhs The right-hand side value for the comparison
+/// @returns true if the values of lhs do not exactly equal to the values of rhs.
+constexpr bool operator!=(const PedestrianProperties& lhs, const PedestrianProperties& rhs) noexcept
+{
+  return !(lhs == rhs);
+}
+
+/// Static object types.
+///
+/// The values are derived from ASAM OSI stationary object type.
+enum class StaticObjectType : std::uint8_t
+{
+  kUnknown = 0,              ///< The type of the static object is unknown.
+  kOther,                    ///< The type of the static object is known, but unspecified.
+  kBridge,                   ///< The object is a bridge.
+  kBuilding,                 ///< The object is a building.
+  kPole,                     ///< The object is a pole (e.g., from a traffic light).
+  kPylon,                    ///< The object is a pylon.
+  kDelineator,               ///< The object is a delineator (e.g., at a construction site).
+  kTree,                     ///< The object is a tree.
+  kBarrier,                  ///< The object is a barrier.
+  kVegetation,               ///< The object is vegetation.
+  kCurbstone,                ///< The object is a curbstone.
+  kWall,                     ///< The object is a wall.
+  kVerticalStructure,        ///< Landmarks corresponding to vertical structures in the environment.
+  kRectangularStructure,     ///< Landmarks corresponding to rectangular structures in the environment, like walls.
+  kOverheadStructure,        ///< Landmarks corresponding to overhead structures in the environment, like sign bridges.
+  kReflectiveStructure,      ///< Landmarks corresponding to reflective structures in the environment, like reflective poles on the road border.
+  kConstructionSiteElement,  ///< Landmarks corresponding to construction site elements in the environment, like beacons.
+  kSpeedBump,                ///< The object is a speed bump.
+  kEmittingStructure         ///< Landmarks corresponding to sources of electromagnetic waves in the environment, like street lights.
 };
 
 /// Additional properties for entity objects of type static
 struct StaticObjectProperties : public EntityProperties
 {
-  /// Type of the static object (bridge, pole,...)
-  StaticObjectType static_object_type{StaticObjectType::kOther};
+  /// Default constructor
+  StaticObjectProperties() noexcept
+      : EntityProperties{EntityType::kStatic} {}
+
+  /// Construct StaticObjectProperties from its members
+  ///
+  /// @param[in] bounding_box The three dimensional bounding box that encloses the entity
+  /// @param[in] model Definition of the model of the entity
+  /// @param[in] properties Additional properties as name value pairs
+  /// @param[in] mass The mass of the entity in kg
+  /// @param[in] static_object_type Type of the static object (bridge, pole,...)
+  /// @param[in] vertical_offset Amount to shift position along lane normal
+  explicit StaticObjectProperties(BoundingBox bounding_box,
+                                  std::string model,
+                                  std::map<std::string, std::string> properties,
+                                  units::mass::kilogram_t mass,
+                                  StaticObjectType static_object_type,
+                                  units::length::meter_t vertical_offset) noexcept
+      : EntityProperties{bounding_box, EntityType::kStatic, std::move(model), std::move(properties), mass}, static_object_type{static_object_type}, vertical_offset{vertical_offset}
+  {
+  }
+
+  /// Destructor
+  ~StaticObjectProperties() noexcept override = default;
+
+  /// Copy constructor
+  /// @param[in] other The object to copy from
+  StaticObjectProperties(const StaticObjectProperties& other) = default;
+
+  /// Copy assignment operator
+  /// @param[in] other The object to copy from
+  /// @returns A reference to this object
+  StaticObjectProperties& operator=(const StaticObjectProperties& other) noexcept = default;
+
+  /// Move constructor
+  /// @param[in] other The object to move from
+  StaticObjectProperties(StaticObjectProperties&& other) noexcept = default;
+
+  /// Move assignment operator
+  /// @param[in] other The object to move from
+  /// @returns A reference to this object
+  StaticObjectProperties& operator=(StaticObjectProperties&& other) noexcept = default;
+
+  StaticObjectType static_object_type{};  ///< Type of the static object (bridge, pole,...)
 
   /// Amount to shift position along lane normal.
   /// It allows static objects like traffic signs to be placed at certain amount above the road.
   /// It is considered when the position of the entity is set.
-  units::length::meter_t vertical_offset{0.0};
+  units::length::meter_t vertical_offset{};
 };
 
+/// Equality comparison for StaticObjectProperties.
+///
+/// @param[in] lhs The left-hand side value for the comparison
+/// @param[in] rhs The right-hand side value for the comparison
+/// @returns true if the values of lhs exactly equal to the values of rhs.
+constexpr bool operator==(const StaticObjectProperties& lhs, const StaticObjectProperties& rhs) noexcept
+{
+  return std::tie(static_cast<const EntityProperties&>(lhs), lhs.static_object_type, lhs.vertical_offset) ==
+         std::tie(static_cast<const EntityProperties&>(rhs), rhs.static_object_type, rhs.vertical_offset);
+}
+
+/// Inequality comparison for StaticObjectProperties.
+///
+/// @param[in] lhs The left-hand side value for the comparison
+/// @param[in] rhs The right-hand side value for the comparison
+/// @returns true if the values of lhs do not exactly equal to the values of rhs.
+constexpr bool operator!=(const StaticObjectProperties& lhs, const StaticObjectProperties& rhs) noexcept
+{
+  return !(lhs == rhs);
+}
+
 }  // namespace mantle_api
 
 #endif  // MANTLEAPI_TRAFFIC_ENTITY_PROPERTIES_H
diff --git a/include/MantleAPI/Traffic/i_controller.h b/include/MantleAPI/Traffic/i_controller.h
index 4afd7b91f1e00c6a27a145bc99bd6229718d2a35..f4b5d9f417b582c28102de0f91c9353f1d0592e6 100644
--- a/include/MantleAPI/Traffic/i_controller.h
+++ b/include/MantleAPI/Traffic/i_controller.h
@@ -1,6 +1,7 @@
 /********************************************************************************
  * Copyright (c) 2021 in-tech GmbH
  *               2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License 2.0 which is available at
@@ -17,6 +18,8 @@
 #define MANTLEAPI_TRAFFIC_I_CONTROLLER_H
 #pragma once
 
+#include <cstdint>
+
 #include "MantleAPI/Common/i_identifiable.h"
 
 namespace mantle_api
@@ -26,23 +29,23 @@ namespace mantle_api
 class IController : public virtual IIdentifiable
 {
 public:
-  /// Desired state of lateral domain
-  enum class LateralState
+  /// Desired state of lateral domain.
+  enum class LateralState : std::uint8_t
   {
-    kNoChange = 0,
-    kActivate,
-    kDeactivate
+    kNoChange = 0,  ///< No change in the state of the lateral domain
+    kActivate,      ///< Activate the lateral domain
+    kDeactivate     ///< Deactivate the lateral domain
   };
 
-  /// Desired state of longitudinal domain
-  enum class LongitudinalState
+  /// Desired state of longitudinal domain.
+  enum class LongitudinalState : std::uint8_t
   {
-    kNoChange = 0,
-    kActivate,
-    kDeactivate
+    kNoChange = 0,  ///< No change in the state of the longitudinal domain
+    kActivate,      ///< Activate the longitudinal domain
+    kDeactivate     ///< Deactivate the longitudinal domain
   };
 
-  /// Change the state of a controller
+  /// Change the state of a controller.
   /// @param[in] lateral_state      New state of the lateral domain
   /// @param[in] longitudinal_state New state of the longituindal domain
   virtual void ChangeState(LateralState lateral_state, LongitudinalState longitudinal_state) = 0;
diff --git a/include/MantleAPI/Traffic/i_controller_config.h b/include/MantleAPI/Traffic/i_controller_config.h
index c3f765ffc73e53f963d7a435b853c17f39b0f593..4fbb9218d69cba95a6fbced9423dc942544c84c3 100644
--- a/include/MantleAPI/Traffic/i_controller_config.h
+++ b/include/MantleAPI/Traffic/i_controller_config.h
@@ -16,10 +16,10 @@
 #ifndef MANTLEAPI_TRAFFIC_I_CONTROLLER_CONFIG_H
 #define MANTLEAPI_TRAFFIC_I_CONTROLLER_CONFIG_H
 
-#include <MantleAPI/Common/route_definition.h>
 #include <MantleAPI/Common/spline.h>
 #include <MantleAPI/Common/vector.h>
 #include <MantleAPI/Map/i_lane_location_query_service.h>
+#include <MantleAPI/Map/routing_definition.h>
 #include <MantleAPI/Traffic/control_strategy.h>
 
 #include <map>
@@ -37,15 +37,15 @@ struct IControllerConfig
   /// @param[in] name               Name of the controller. Might be ignored by the environment.
   /// @param[in] map_query_service  Pointer to the map query service
   /// @param[in] control_strategies List of active control strategies
-  /// @param[in] route_definition   Specifies the route behavior for the control stratgies
+  /// @param[in] routing_definition Specifies the route behavior for the control stratgies
   explicit IControllerConfig(std::string name = {},
                              ILaneLocationQueryService* map_query_service = nullptr,
                              std::vector<std::shared_ptr<mantle_api::ControlStrategy>> control_strategies = {},
-                             RouteDefinition route_definition = {})
+                             RoutingDefinition routing_definition = {})
       : name{std::move(name)},
         map_query_service{map_query_service},
         control_strategies{std::move(control_strategies)},
-        route_definition{std::move(route_definition)} {}
+        routing_definition{std::move(routing_definition)} {}
 
   /// @brief default destructor
   virtual ~IControllerConfig() = default;
@@ -56,8 +56,8 @@ struct IControllerConfig
   ILaneLocationQueryService* map_query_service;
   /// List of active control strategies
   std::vector<std::shared_ptr<mantle_api::ControlStrategy>> control_strategies;
-  /// Specifies the route behavior for the control stratgies
-  RouteDefinition route_definition;
+  /// Specifies the routing behavior for the control stratgies
+  RoutingDefinition routing_definition;
 };
 
 /// @brief Equality comparison for IControllerConfig.
@@ -86,7 +86,7 @@ inline bool operator==(const IControllerConfig& lhs, const IControllerConfig& rh
   return lhs.name == rhs.name &&
          lhs.map_query_service == rhs.map_query_service &&
          std::equal(lhs.control_strategies.begin(), lhs.control_strategies.end(), rhs.control_strategies.begin(), rhs.control_strategies.end(), compare_control_strategy) &&
-         lhs.route_definition == rhs.route_definition;
+         lhs.routing_definition == rhs.routing_definition;
 }
 
 /// @brief Check for not equal
diff --git a/include/MantleAPI/Traffic/i_controller_repository.h b/include/MantleAPI/Traffic/i_controller_repository.h
index 13c0d672330d6ea7b448e017aa59fc94c6a7759d..77dc13b2ffb59329b2464de697568f2420933ffd 100644
--- a/include/MantleAPI/Traffic/i_controller_repository.h
+++ b/include/MantleAPI/Traffic/i_controller_repository.h
@@ -1,6 +1,7 @@
 /********************************************************************************
  * Copyright (c) 2021 in-tech GmbH
  *               2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License 2.0 which is available at
@@ -17,54 +18,55 @@
 #define MANTLEAPI_TRAFFIC_I_CONTROLLER_REPOSITORY_H
 #pragma once
 
+#include <memory>
+
 #include "MantleAPI/Traffic/i_controller.h"
 #include "MantleAPI/Traffic/i_controller_config.h"
 
 namespace mantle_api
 {
-/// This interface provides CRUD functionality for controllers.
-/// Controller, which is assigned to exactly one entity, controls that one entity by enforcing the behavior prescribed by
-/// the control strategies assigned to that entity.
-/// Multiple controllers can be assigned to an entity, but only one controller can be activated for an entity at a time.
+/// This interface provides CRUD functionality for IControllers.
+/// An IController, which is assigned to exactly one IEntity, controls that one IEntity by enforcing the behavior prescribed by
+/// the ControlStrategies assigned to that IEntity.
+/// Multiple controllers can be assigned to one IEntity, but only one controller can be activated for an IEntity at any time.
 class IControllerRepository
 {
 public:
   virtual ~IControllerRepository() = default;
 
-  /// Creates a new controller for the entity
+  /// Create a new IController.
   ///
-  /// @param config Controller config
-  /// @return newly created controller for the entity
-  virtual IController& Create(std::unique_ptr<IControllerConfig> config) = 0;
+  /// @param config IControllerConfig
+  /// @return The newly created IController
+  virtual std::weak_ptr<IController> Create(std::unique_ptr<IControllerConfig> config) = 0;
 
-  /// @deprecated Creates a new controller for the entity
+  /// @deprecated Create a new IController.
   ///
-  /// @param id     Unique ID of the controller
-  /// @param config Controller config
-  /// @return newly created controller for the entity
-  [[deprecated]] virtual IController& Create(UniqueId id, std::unique_ptr<IControllerConfig> config) = 0;  // deprecated
+  /// @param id     UniqueId of the controller
+  /// @param config IControllerConfig
+  /// @return The newly created IController
+  [[deprecated]] virtual std::weak_ptr<IController> Create(UniqueId id, std::unique_ptr<IControllerConfig> config) = 0;  // deprecated
 
-  /// Gets the controller by the given unique ID
+  /// Get the IController by the given UniqueId.
   ///
-  /// @param id Unique ID of the controller
-  /// @return controller according to the given unique ID
-  virtual std::optional<std::reference_wrapper<IController>> Get(UniqueId id) = 0;
+  /// @param id UniqueId of the IController
+  /// @return IController with to the given UniqueId
+  virtual std::weak_ptr<IController> Get(UniqueId id) = 0;
 
-  /// Checks whether the internal management container contains a controller with the given ID
+  /// Check whether the repository contains an IController with the given UniqueId.
   ///
-  /// @param id Unique ID to be searched for
-  /// @return true, if controller with given ID exists, otherwise false
+  /// @param id UniqueId to be searched for
+  /// @return true, if an IController with given UniqueId exists, false otherwise
   [[nodiscard]] virtual bool Contains(UniqueId id) const = 0;
 
-  /// Deletes the controller
+  /// Delete the IController from the scenario.
   ///
-  /// @param id The Identifier of the controller to be deleted
+  /// @param id The UniqueId of the IController to be deleted
   virtual void Delete(UniqueId id) = 0;
 
-  /// Resets the controller repository
+  /// Reset the IControllerRepository.
   ///
-  /// Establishes a defined initial state,
-  /// such as removing all controllers
+  /// Establish a defined initial state, such as removing all IControllers.
   virtual void Reset() = 0;
 };
 
diff --git a/include/MantleAPI/Traffic/i_entity.h b/include/MantleAPI/Traffic/i_entity.h
index fd4ab6da19b307618b925803b43169087284ab9f..5b8a315944eba817abd6838be08498fb0adaa611 100644
--- a/include/MantleAPI/Traffic/i_entity.h
+++ b/include/MantleAPI/Traffic/i_entity.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2021-2025, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -17,11 +18,16 @@
 
 #include <MantleAPI/Common/bounding_box.h>
 #include <MantleAPI/Common/i_identifiable.h>
+#include <MantleAPI/Common/orientation.h>
 #include <MantleAPI/Common/pose.h>
+#include <MantleAPI/Map/i_route.h>
 #include <MantleAPI/Traffic/entity_properties.h>
 #include <MantleAPI/Traffic/i_controller_config.h>
+#include <units.h>
 
+#include <cstdint>
 #include <memory>
+#include <string>
 #include <vector>
 
 namespace mantle_api
@@ -45,7 +51,7 @@ struct EntityVisibilityConfig
   /// sensor the entity would be not visible / not contained in its OSI Sensor View.
   /// - When "sensor_names" is not specified (empty vector) then the "sensors" flag applies to
   /// all sensors.
-  std::vector<std::string> sensor_names{};
+  std::vector<std::string> sensor_names;
 };
 
 /// Base interface for all static and dynamic scenario entities.
@@ -97,8 +103,7 @@ public:
   /// @brief Sets the orientation rate (angular velocity) of the scenario entity
   ///
   /// @param orientation_rate Rate of change of a scenario entity's orientation over time
-  virtual void SetOrientationRate(
-      const Orientation3<units::angular_velocity::radians_per_second_t>& orientation_rate) = 0;
+  virtual void SetOrientationRate(const Orientation3<units::angular_velocity::radians_per_second_t>& orientation_rate) = 0;
 
   /// @brief Get the orientation rate (angular velocity) of the scenario entity
   ///
@@ -108,14 +113,12 @@ public:
   /// @brief Sets the orientation acceleration (angular acceleration) of the scenario entity
   ///
   /// @param orientation_acceleration Rate of change of a scenario entity's orientation rate with respect to time
-  virtual void SetOrientationAcceleration(
-      const Orientation3<units::angular_acceleration::radians_per_second_squared_t>& orientation_acceleration) = 0;
+  virtual void SetOrientationAcceleration(const Orientation3<units::angular_acceleration::radians_per_second_squared_t>& orientation_acceleration) = 0;
 
   /// @brief Get the orientation acceleration (angular acceleration) of the scenario entity
   ///
   /// @return Orientation acceleration (angular acceleration)
-  [[nodiscard]] virtual Orientation3<units::angular_acceleration::radians_per_second_squared_t> GetOrientationAcceleration()
-      const = 0;
+  [[nodiscard]] virtual Orientation3<units::angular_acceleration::radians_per_second_squared_t> GetOrientationAcceleration() const = 0;
 
   /// @brief Sets the properties that describe scenario entity
   ///
@@ -130,12 +133,12 @@ public:
   /// @brief Sets the IDs of the lanes that scenario entity is assigned to
   ///
   /// @param assigned_lane_ids The IDs of the lanes that scenario entity is assigned to
-  virtual void SetAssignedLaneIds(const std::vector<std::uint64_t>& assigned_lane_ids) = 0;
+  virtual void SetAssignedLaneIds(const std::vector<mantle_api::UniqueId>& assigned_lane_ids) = 0;
 
   /// @brief Get the IDs of the lanes that scenario entity is assigned to
   ///
   /// @return IDs of the lanes that scenario entity is assigned to
-  [[nodiscard]] virtual std::vector<std::uint64_t> GetAssignedLaneIds() const = 0;
+  [[nodiscard]] virtual std::vector<mantle_api::UniqueId> GetAssignedLaneIds() const = 0;
 
   /// @brief Sets the visibility of the scenario entity
   ///
@@ -146,6 +149,22 @@ public:
   ///
   /// @return Visibility of the scenario entity
   [[nodiscard]] virtual EntityVisibilityConfig GetVisibility() const = 0;
+
+  /// Set the route for the scenario entity.
+  ///
+  /// If the entities' position is on the route,
+  /// the entity should follow the route from this position.
+  /// If the entities' position is NOT on the route,
+  /// the entity should navigate towards the beginning of the route.
+  /// TODO: we loose RoutingStrategy of first RoutingWaypoint
+  ///
+  /// @param route Route of the scenario entity
+  virtual void SetRoute(const std::weak_ptr<const IRoute>& route) = 0;
+
+  /// Get the route of the scenario entity.
+  ///
+  /// @return Route of the scenario entity if one has been assigned
+  [[nodiscard]] virtual std::weak_ptr<const IRoute> GetRoute() const = 0;
 };
 
 /// Interface for dynamic scenario entities of vehicle type
diff --git a/include/MantleAPI/Traffic/i_entity_repository.h b/include/MantleAPI/Traffic/i_entity_repository.h
index cfaeafb9b6fc982599d1615c174cf1372ffd583f..80dac079fec22f5ad77fe67c2820cc314cfab2b9 100644
--- a/include/MantleAPI/Traffic/i_entity_repository.h
+++ b/include/MantleAPI/Traffic/i_entity_repository.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2021-2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -19,133 +20,126 @@
 #include <MantleAPI/Traffic/i_entity.h>
 
 #include <functional>
-#include <optional>
+#include <memory>
 #include <string>
 #include <vector>
 
 namespace mantle_api
 {
 
-/// This interface provides CRUD functionality for scenario entities.
+/// This interface provides CRUD functionality for IEntities.
 class IEntityRepository
 {
 public:
   virtual ~IEntityRepository() = default;
 
-  /// Creates a new dynamic scenario entity of vehicle type
+  /// Create a new IVehicle.
   ///
-  /// @param name       The name of the entity to be created
-  /// @param properties Vehicle properties
-  /// @return newly created dynamic scenario entity of vehicle type
-  virtual IVehicle& Create(const std::string& name, const VehicleProperties& properties) = 0;
+  /// @param name       The name of the IVehicle to be created
+  /// @param properties VehicleProperties
+  /// @return The newly created IVehicle
+  virtual std::weak_ptr<IVehicle> Create(const std::string& name, const VehicleProperties& properties) = 0;
 
-  /// @deprecated Creates a new dynamic scenario entity of vehicle type
+  /// @deprecated Create a new IVehicle.
   ///
-  /// @param id         Unique ID of the entity
-  /// @param name       The name of the entity to be created
-  /// @param properties Vehicle properties
-  /// @return newly created dynamic scenario entity of vehicle type
-  [[deprecated]] virtual IVehicle& Create(UniqueId id, const std::string& name, const VehicleProperties& properties) = 0;
+  /// @param id         UniqueId of the IVehicle
+  /// @param name       The name of the IVehicle to be created
+  /// @param properties VehicleProperties
+  /// @return The newly created IVehicle
+  [[deprecated]] virtual std::weak_ptr<IVehicle> Create(UniqueId id, const std::string& name, const VehicleProperties& properties) = 0;
 
-  /// Creates a new scenario entity of pedestrian type
+  /// Create a new IPedestrian.
   ///
-  /// @param name       The name of the entity to be created
-  /// @param properties Pedestrian properties
-  /// @return newly created scenario entity of pedestrian type
-  virtual IPedestrian& Create(const std::string& name, const PedestrianProperties& properties) = 0;
+  /// @param name       The name of the IPedestrian to be created
+  /// @param properties PedestrianProperties
+  /// @return The newly created IPedestrian
+  virtual std::weak_ptr<IPedestrian> Create(const std::string& name, const PedestrianProperties& properties) = 0;
 
-  /// @deprecated Creates a new scenario entity of pedestrian type
+  /// @deprecated Create a new IPedestrian.
   ///
-  /// @param id         Unique ID of the entity
-  /// @param name       The name of the entity to be created
-  /// @param properties Pedestrian properties
-  /// @return newly created scenario entity of pedestrian type
-  [[deprecated]] virtual IPedestrian& Create(UniqueId id, const std::string& name, const PedestrianProperties& properties) = 0;
+  /// @param id         UniqueId of the IPedestrian
+  /// @param name       The name of the IPedestrian to be created
+  /// @param properties PedestrianProperties
+  /// @return The newly created IPedestrian
+  [[deprecated]] virtual std::weak_ptr<IPedestrian> Create(UniqueId id, const std::string& name, const PedestrianProperties& properties) = 0;
 
-  /// Creates a new scenario entity of static object type
+  /// Create a new IStaticObject.
   ///
-  /// @param name       The name of the entity to be created
-  /// @param properties Static object properties
-  /// @return newly created scenario entity of static object type
-  virtual IStaticObject& Create(const std::string& name, const mantle_api::StaticObjectProperties& properties) = 0;
+  /// @param name       The name of the IStaticObject to be created
+  /// @param properties StaticObjectProperties
+  /// @return The newly created IStaticObject
+  virtual std::weak_ptr<IStaticObject> Create(const std::string& name, const mantle_api::StaticObjectProperties& properties) = 0;
 
-  /// @deprecated Creates a new scenario entity of static object type
+  /// @deprecated Create a new IStaticObject.
   ///
-  /// @param id         Unique ID of the entity
-  /// @param name       The name of the entity to be created
-  /// @param properties Static object properties
-  /// @return newly created scenario entity of static object type
-  [[deprecated]] virtual IStaticObject& Create(UniqueId id, const std::string& name, const StaticObjectProperties& properties) = 0;
+  /// @param id         UniqueId of the IStaticObject
+  /// @param name       The name of the IStaticObject to be created
+  /// @param properties StaticObjectProperties
+  /// @return The newly created IStaticObject
+  [[deprecated]] virtual std::weak_ptr<IStaticObject> Create(UniqueId id, const std::string& name, const StaticObjectProperties& properties) = 0;
 
-  /// Gets the host vehicle
+  /// Get the host vehicle.
   ///
-  /// @return host vehicle
-  virtual IVehicle& GetHost() = 0;
+  /// @return The host vehicle
+  virtual std::weak_ptr<IVehicle> GetHost() = 0;
 
-  /// Gets the entity by the given name
+  /// Get the IEntity by the given name.
   ///
-  /// @param name The name of the entity
-  /// @return entity according to the given name
-  virtual std::optional<std::reference_wrapper<IEntity>> Get(const std::string& name) = 0;
+  /// @param name The name of the IEntity
+  /// @return The IEntity with the given name
+  virtual std::weak_ptr<IEntity> Get(const std::string& name) = 0;
 
-  /// Gets the const entity by the given name
-  ///
-  /// @param name The name of the entity
-  /// @return const entity according to the given name
-  [[nodiscard]] virtual std::optional<std::reference_wrapper<const IEntity>> Get(const std::string& name) const = 0;
+  /// @copydoc Get(const std::string&)
+  [[nodiscard]] virtual std::weak_ptr<const IEntity> Get(const std::string& name) const = 0;
 
-  /// Gets the entity by the given unique ID
+  /// Get the IEntity by the given UniqueId.
   ///
-  /// @param id Unique ID of the entity
-  /// @return entity according to the given unique ID
-  virtual std::optional<std::reference_wrapper<IEntity>> Get(UniqueId id) = 0;
+  /// @param id The UniqueId of the IEntity
+  /// @return The IEntity with the given UniqueId
+  virtual std::weak_ptr<IEntity> Get(UniqueId id) = 0;
 
-  /// Gets the const entity by the given unique ID
-  ///
-  /// @param id Unique ID of the entity
-  /// @return const entity according to the given unique ID
-  [[nodiscard]] virtual std::optional<std::reference_wrapper<const IEntity>> Get(UniqueId id) const = 0;
+  /// @copydoc Get(UniqueId)
+  [[nodiscard]] virtual std::weak_ptr<const IEntity> Get(UniqueId id) const = 0;
 
-  /// Checks whether the internal management container contains an scenario entity with the given ID
+  /// Check whether the repository contains an IEntity with the given UniqueId.
   ///
-  /// @param id Unique ID to be searched for
-  /// @return true, if scenario entity with given ID exists, otherwise false
+  /// @param id The UniqueId to be searched for
+  /// @return true, if an IEntity with given UniqueId exists, false otherwise
   [[nodiscard]] virtual bool Contains(UniqueId id) const = 0;
 
-  /// Deletes the reference entity from the scenario
+  /// Delete the IEntity from the scenario.
   ///
-  /// @param name The name of the entity to be deleted
+  /// @param name The name of the IEntity to be deleted
   virtual void Delete(const std::string& name) = 0;
 
-  /// Resets the entity repository
+  /// Reset the IEntityRepository.
   ///
-  /// Establishes a defined initial state,
-  /// such as removing all entities
+  /// Establish a defined initial state, such as removing all IEntities.
   virtual void Reset() = 0;
 
-  /// Deletes the reference entity from the scenario
+  /// Delete the IEntity from the scenario.
   ///
-  /// @param id The Identifier of the scenario entity to be deleted
+  /// @param id The UniqueId of the IEntity to be deleted
   virtual void Delete(UniqueId id) = 0;
 
-  /// Gets all scenario entities
+  /// Get all IEntities.
   ///
-  /// @returns all scenario entities
-  [[nodiscard]] virtual const std::vector<std::unique_ptr<mantle_api::IEntity>>& GetEntities() const = 0;
+  /// @returns All IEntities
+  [[nodiscard]] virtual std::vector<std::weak_ptr<IEntity>> GetEntities() const = 0;
 
-  /// Allows an external component to react on creation of an entity, such as establishing additional references pointing to it
+  /// Allow an external component to react to the creation of an IEntity, such as establishing additional references pointing to it.
   ///
-  /// @param callback Function to be called when creating an entity
-  virtual void RegisterEntityCreatedCallback(const std::function<void(IEntity&)>& callback) = 0;
+  /// @param callback Function to be called when creating an IEntity
+  virtual void RegisterEntityCreatedCallback(const std::function<void(std::weak_ptr<IEntity>)>& callback) = 0;
 
-  /// Allows an external component to react on deletion of an entity, such as cleaning up invalid references pointing to it
+  /// Allow an external component to react to the deletion of an IEntity, such as cleaning up invalid references pointing to it.
   ///
-  /// @param callback Function to be called when deleting an entity with string parameter
+  /// @param callback Function to be called when deleting an IEntity with string parameter
   virtual void RegisterEntityDeletedCallback(const std::function<void(const std::string&)>& callback) = 0;
 
-  /// Allows an external component to react on deletion of an entity, such as cleaning up invalid references pointing to it
+  /// Allow an external component to react to the deletion of an IEntity, such as cleaning up invalid references pointing to it.
   ///
-  /// @param callback Function to be called when deleting an entity with UniqueId parameter
+  /// @param callback Function to be called when deleting an IEntity with UniqueId parameter
   virtual void RegisterEntityDeletedCallback(const std::function<void(UniqueId)>& callback) = 0;
 };
 
diff --git a/include/MantleAPI/Traffic/i_traffic_area_stream.h b/include/MantleAPI/Traffic/i_traffic_area_stream.h
index d9f0565bc1bd9e1fa844d23e98e2795608a39a40..7b919aa1586d02219aff7f07dac1fab4bd712390 100644
--- a/include/MantleAPI/Traffic/i_traffic_area_stream.h
+++ b/include/MantleAPI/Traffic/i_traffic_area_stream.h
@@ -65,7 +65,7 @@ public:
   /// @param start_distance   Distance from which to start the search
   /// @param search_distance  Distance to search for in the search_direction
   /// @returns Entity or empty if no entity was found
-  virtual const IEntity* GetEntity(
+  virtual std::weak_ptr<IEntity> GetEntity(
       SearchDirection search_direction,
       units::length::meter_t start_distance,
       units::length::meter_t search_distance) const = 0;
diff --git a/include/MantleAPI/Traffic/i_traffic_swarm_service.h b/include/MantleAPI/Traffic/i_traffic_swarm_service.h
index 59fdb07eb87facb64702f0cc798df79faa629589..311946b82e470fb85bedff017853b70b8ff830f5 100644
--- a/include/MantleAPI/Traffic/i_traffic_swarm_service.h
+++ b/include/MantleAPI/Traffic/i_traffic_swarm_service.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -19,7 +20,11 @@
 #include <MantleAPI/Common/vector.h>
 #include <units.h>
 
+#include <cstddef>
+#include <cstdint>
 #include <memory>
+#include <string>
+#include <utility>
 #include <vector>
 
 #include "MantleAPI/Traffic/entity_properties.h"
@@ -41,7 +46,7 @@ struct TrafficSwarmParameters
   /// Name of the central entity the swarm traffic is created around
   std::string central_entity_name;
   /// The maximum number of vehicles surrounding the central entity
-  size_t maximum_number_of_vehicles;
+  std::size_t maximum_number_of_vehicles;
   /// The starting speeds of the spawned entities
   SpeedRange speed_range;
   /// Radius of the inner circular area around the central entity
@@ -62,11 +67,11 @@ class ITrafficSwarmService
 public:
   virtual ~ITrafficSwarmService() = default;
 
-  /// Specify the relative position of the spawned vehicle to the central entity
-  enum class RelativePosition
+  /// Specify the relative position of the spawned vehicle to the central entity.
+  enum class RelativePosition : std::uint8_t
   {
-    kInFront = 0,
-    kBehind
+    kInFront = 0,  ///< The spawned vehicle is in front of the central entity
+    kBehind        ///< The spawned vehicle is behind the central entity
   };
 
   /// Specify the position of the spawned vehicle
@@ -92,7 +97,7 @@ public:
   /// Sets the number of swarm entities
   ///
   /// @param count number of swarm entities
-  virtual void SetSwarmEntitiesCount(size_t count) = 0;
+  virtual void SetSwarmEntitiesCount(std::size_t count) = 0;
 };
 
 }  // namespace mantle_api
diff --git a/include/MantleAPI/Traffic/traffic_light_properties.h b/include/MantleAPI/Traffic/traffic_light_properties.h
index cb13783542537794dca77657338a937fb9438b02..3114a9c28c87572f01d5c0fc9f9c48dcea2b244d 100644
--- a/include/MantleAPI/Traffic/traffic_light_properties.h
+++ b/include/MantleAPI/Traffic/traffic_light_properties.h
@@ -1,5 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2021-2023, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  *
  * This program and the accompanying materials are made
  * available under the terms of the Eclipse Public License 2.0
@@ -17,32 +18,33 @@
 
 #include <MantleAPI/Common/time_utils.h>
 
+#include <cstdint>
 #include <vector>
 
 namespace mantle_api
 {
 
 /// Specify the color of a traffic light bulb.
-enum class TrafficLightBulbColor
+enum class TrafficLightBulbColor : std::uint8_t
 {
-  kUnknown = 0,
-  kOther = 1,
-  kRed = 2,
-  kYellow = 3,
-  kGreen = 4,
-  kBlue = 5,
-  kWhite = 6
+  kUnknown = 0,  ///< The color of the traffic light bulb is unknown.
+  kOther,        ///< The color of the traffic light bulb is known, but unspecified.
+  kRed,          ///< The color of the traffic light bulb is red.
+  kYellow,       ///< The color of the traffic light bulb is yellow.
+  kGreen,        ///< The color of the traffic light bulb is green.
+  kBlue,         ///< The color of the traffic light bulb is blue.
+  kWhite         ///< The color of the traffic light bulb is white.
 };
 
 /// Specify the mode of a traffic light bulb.
-enum class TrafficLightBulbMode
+enum class TrafficLightBulbMode : std::uint8_t
 {
-  kUnknown = 0,
-  kOther = 1,
-  kOff = 2,
-  kConstant = 3,
-  kFlashing = 4,
-  kCounting = 5
+  kUnknown = 0,  ///< The mode of the traffic light bulb is unknown.
+  kOther,        ///< The mode of the traffic light bulb is known, but unspecified.
+  kOff,          ///< The traffic light bulb is off.
+  kConstant,     ///< The traffic light bulb is constantly glowing.
+  kFlashing,     ///< The traffic light bulb is flashing.
+  kCounting      ///< The traffic light bulb is counting, i.e. pedestrian traffic lights in the US.
 };
 
 /// Definition of the traffic light state
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 263bd52d3833294186b635d385cae18ca0fd5a9f..2a67193e1a7451d89d027686a473ce7abb8d2607 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -15,21 +15,20 @@ CPMAddPackage(
   OPTIONS "INSTALL_GTEST ${MantleAPI_INSTALL_MOCKS}" "gtest_force_shared_crt ON"
 )
 
-# Generate a translation unit that includes all interface headers
-list(TRANSFORM INTERFACE_HEADER_SET PREPEND "#include \"")
-list(TRANSFORM INTERFACE_HEADER_SET APPEND "\"\n")
-file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/verify_interface_header_set.cpp" ${INTERFACE_HEADER_SET})
-
-add_executable(MantleAPITest)
-
-target_sources(MantleAPITest PUBLIC interface_test.cpp "${CMAKE_CURRENT_BINARY_DIR}/verify_interface_header_set.cpp")
-
-target_include_directories(MantleAPITest PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/test>)
-
-target_link_libraries(MantleAPITest PUBLIC MantleAPI::MantleAPI GTest::gmock_main)
-
-include(GoogleTest)
-gtest_discover_tests(MantleAPITest)
+# Generate translation units for the interface headers to ensure that they are self-contained.
+#
+# FIXME: Replace with CMake 3.24's VERIFY_INTERFACE_HEADER_SETS property when available.
+set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+set(VERIFIY_HEADER_SET_SOURCE_FILES)
+foreach(INTERFACE_HEADER IN LISTS INTERFACE_HEADER_SET)
+  get_filename_component(INTERFACE_HEADER_NAME ${INTERFACE_HEADER} NAME_WLE)
+  set(SOURCE_FILE "${CMAKE_CURRENT_BINARY_DIR}/verify_interface_header_set/${INTERFACE_HEADER_NAME}.cc")
+  file(WRITE "${SOURCE_FILE}" "#include \"${INTERFACE_HEADER}\"\n")
+  list(APPEND VERIFIY_HEADER_SET_SOURCE_FILES "${SOURCE_FILE}")
+endforeach()
+add_library(verify_interface_header_set OBJECT EXCLUDE_FROM_ALL)
+target_sources(verify_interface_header_set PRIVATE "${VERIFIY_HEADER_SET_SOURCE_FILES}")
+target_link_libraries(verify_interface_header_set PUBLIC MantleAPI::MantleAPI)
 
 add_subdirectory(MantleAPI)
 
diff --git a/test/MantleAPI/CMakeLists.txt b/test/MantleAPI/CMakeLists.txt
index 98b494b97e35f2c68a46bc878cb5c36ed9b86229..905d44fbf94bdb20d8aa385d0a2836666e99f902 100644
--- a/test/MantleAPI/CMakeLists.txt
+++ b/test/MantleAPI/CMakeLists.txt
@@ -10,3 +10,5 @@
 
 add_subdirectory(Common)
 add_subdirectory(Execution)
+add_subdirectory(Map)
+add_subdirectory(Traffic)
diff --git a/test/MantleAPI/Common/CMakeLists.txt b/test/MantleAPI/Common/CMakeLists.txt
index 9920800bd3dbf30b6b20f750bede30a74655355f..3a0d5005631c524831b7f663861771af89637004 100644
--- a/test/MantleAPI/Common/CMakeLists.txt
+++ b/test/MantleAPI/Common/CMakeLists.txt
@@ -1,5 +1,5 @@
 ################################################################################
-# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH
+# Copyright (c) 2023-2024 Mercedes-Benz Tech Innovation GmbH
 #
 # This program and the accompanying materials are made available under the terms
 # of the Eclipse Public License 2.0 which is available at
@@ -9,7 +9,25 @@
 ################################################################################
 
 add_executable(CommonTest)
-target_sources(CommonTest PUBLIC floating_point_helper_test.cc logger_test.cc log_utils_test.cc clothoid_spline_test.cc trajectory_test.cc)
+target_sources(
+  CommonTest
+  PUBLIC bounding_box_test.cc
+         clothoid_spline_test.cc
+         dimension_test.cc
+         meta_test.cc
+         floating_point_helper_test.cc
+         geometry_helper_test.cc
+         identifiable_test.cc
+         identifier_test.cc
+         logger_test.cc
+         orientation_test.cc
+         poly_line_test.cc
+         pose_test.cc
+         position_test.cc
+         spline_test.cc
+         trajectory_test.cc
+         vector_test.cc
+)
 target_include_directories(CommonTest PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/test>)
 target_link_libraries(CommonTest PUBLIC MantleAPI::MantleAPI GTest::gmock_main)
 
diff --git a/test/MantleAPI/Common/bounding_box_test.cc b/test/MantleAPI/Common/bounding_box_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a6cef9625887fb2d948cc99aedacf414d5fa1ee6
--- /dev/null
+++ b/test/MantleAPI/Common/bounding_box_test.cc
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include "MantleAPI/Common/bounding_box.h"
+
+#include <gtest/gtest.h>
+#include <units.h>
+
+#include <sstream>
+#include <type_traits>
+
+namespace mantle_api
+{
+
+using ::units::literals::operator""_m;
+
+static_assert(std::is_trivial_v<BoundingBox>);
+
+TEST(BoundingBoxTest, OperatorEqual)
+{
+  constexpr const auto lhs = BoundingBox{{1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}};
+  constexpr const auto rhs = BoundingBox{{1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}};
+
+  ASSERT_EQ(lhs, rhs);
+
+  static_assert(lhs == rhs);
+}
+
+TEST(BoundingBoxTest, OperatorNotEqual)
+{
+  constexpr const auto lhs = BoundingBox{{1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}};
+  constexpr const auto rhs = BoundingBox{{2_m, 2_m, 2_m}, {2_m, 2_m, 2_m}};
+
+  ASSERT_NE(lhs, rhs);
+
+  static_assert(lhs != rhs);
+}
+
+TEST(BoundingBoxTest, OutputStreamOperator)
+{
+  const auto bbox = BoundingBox{{1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}};
+
+  auto oss = std::ostringstream{};
+  oss << bbox;
+
+  ASSERT_EQ(oss.str(), "BoundingBox(.geometric_center=Vec3(.x=1 m, .y=1 m, .z=1 m), .dimension=Dimension3(.length=1 m, .width=1 m, .height=1 m))");
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Common/dimension_test.cc b/test/MantleAPI/Common/dimension_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4ccbd92618a6a72221198bb00e1eb55cbed2bbf9
--- /dev/null
+++ b/test/MantleAPI/Common/dimension_test.cc
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include "MantleAPI/Common/dimension.h"
+
+#include <gtest/gtest.h>
+#include <units.h>
+
+#include <sstream>
+#include <type_traits>
+
+namespace mantle_api
+{
+
+using ::units::literals::operator""_m;
+
+static_assert(std::is_trivial_v<Dimension3>);
+
+TEST(Dimension3Test, OperatorEqual)
+{
+  constexpr const auto lhs = Dimension3{1_m, 1_m, 1_m};
+  constexpr const auto rhs = Dimension3{1_m, 1_m, 1_m};
+
+  ASSERT_EQ(lhs, rhs);
+
+  static_assert(lhs == rhs);
+}
+
+TEST(Dimension3Test, OperatorNotEqual)
+{
+  constexpr const auto lhs = Dimension3{1_m, 1_m, 1_m};
+  constexpr const auto rhs = Dimension3{2_m, 2_m, 2_m};
+
+  ASSERT_NE(lhs, rhs);
+
+  static_assert(lhs != rhs);
+}
+
+TEST(Dimension3Test, OutputStreamOperator)
+{
+  const auto dim = Dimension3{1_m, 1_m, 1_m};
+
+  auto oss = std::ostringstream{};
+  oss << dim;
+
+  ASSERT_EQ(oss.str(), "Dimension3(.length=1 m, .width=1 m, .height=1 m)");
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Common/floating_point_helper_test.cc b/test/MantleAPI/Common/floating_point_helper_test.cc
index ef9922aec0469aeb6ca47f370388ec8b7403849b..2915fab412ab6ed3dddd7760efc05e3c98643bbf 100644
--- a/test/MantleAPI/Common/floating_point_helper_test.cc
+++ b/test/MantleAPI/Common/floating_point_helper_test.cc
@@ -14,13 +14,11 @@
 #include <units.h>
 
 #include <limits>
+#include <tuple>
 
-namespace
+namespace mantle_api
 {
 
-using mantle_api::AlmostEqual;
-using mantle_api::GreaterOrEqual;
-using mantle_api::LessOrEqual;
 using units::length::meter_t;
 
 //
@@ -82,6 +80,19 @@ static_assert(LessOrEqual(-kDoubleInfinity, kDoubleLowest));
 static_assert(LessOrEqual(kDoubleLargeWithFractional, kDoubleLarge, kDoubleCustomEpsilon));
 static_assert(!LessOrEqual(kDoubleLargeWithFractional, kDoubleLarge, kDoubleCustomEpsilon, true));
 
+// AlmostEqual with tuples
+static_assert(AlmostEqual(std::tie(kDoubleZero), std::tie(kDoubleZero)));
+static_assert(AlmostEqual(std::tie(kDoubleZero, kDoubleZero), std::tie(kDoubleZero, kDoubleZero)));
+static_assert(AlmostEqual(std::tie(kDoubleZero, kDoubleZero, kDoubleZero), std::tie(kDoubleZero, kDoubleZero, kDoubleZero)));
+
+static_assert(!AlmostEqual(std::tie(kDoubleMax), std::tie(kDoubleZero)));
+static_assert(!AlmostEqual(std::tie(kDoubleZero, kDoubleMax), std::tie(kDoubleZero, kDoubleZero)));
+static_assert(!AlmostEqual(std::tie(kDoubleZero, kDoubleZero, kDoubleMax), std::tie(kDoubleZero, kDoubleZero, kDoubleZero)));
+
+static_assert(AlmostEqual(std::tie(kDoubleZero), std::tie(kDoubleZero), kDoubleCustomEpsilon, true));
+static_assert(AlmostEqual(std::tie(kDoubleZero, kDoubleZero), std::tie(kDoubleZero, kDoubleZero), kDoubleCustomEpsilon, true));
+static_assert(AlmostEqual(std::tie(kDoubleZero, kDoubleZero, kDoubleZero), std::tie(kDoubleZero, kDoubleZero, kDoubleZero), kDoubleCustomEpsilon, true));
+
 //
 // float
 //
@@ -141,6 +152,19 @@ static_assert(LessOrEqual(-kFloatInfinity, kFloatLowest));
 static_assert(LessOrEqual(kFloatLargeWithFractional, kFloatLarge, kFloatCustomEpsilon));
 static_assert(!LessOrEqual(kFloatLargeWithFractional, kFloatLarge, kFloatCustomEpsilon, true));
 
+// AlmostEqual with tuples
+static_assert(AlmostEqual(std::tie(kFloatZero), std::tie(kFloatZero)));
+static_assert(AlmostEqual(std::tie(kFloatZero, kFloatZero), std::tie(kFloatZero, kFloatZero)));
+static_assert(AlmostEqual(std::tie(kFloatZero, kFloatZero, kFloatZero), std::tie(kFloatZero, kFloatZero, kFloatZero)));
+
+static_assert(!AlmostEqual(std::tie(kFloatMax), std::tie(kFloatZero)));
+static_assert(!AlmostEqual(std::tie(kFloatZero, kFloatMax), std::tie(kFloatZero, kFloatZero)));
+static_assert(!AlmostEqual(std::tie(kFloatZero, kFloatZero, kFloatMax), std::tie(kFloatZero, kFloatZero, kFloatZero)));
+
+static_assert(AlmostEqual(std::tie(kFloatZero), std::tie(kFloatZero), kFloatCustomEpsilon, true));
+static_assert(AlmostEqual(std::tie(kFloatZero, kFloatZero), std::tie(kFloatZero, kFloatZero), kFloatCustomEpsilon, true));
+static_assert(AlmostEqual(std::tie(kFloatZero, kFloatZero, kFloatZero), std::tie(kFloatZero, kFloatZero, kFloatZero), kFloatCustomEpsilon, true));
+
 //
 // meter_t
 //
@@ -200,4 +224,22 @@ static_assert(LessOrEqual(-kMeterInfinity, kMeterLowest));
 static_assert(LessOrEqual(kMeterLargeWithFractional, kMeterLarge, kMeterCustomEpsilon));
 static_assert(!LessOrEqual(kMeterLargeWithFractional, kMeterLarge, kMeterCustomEpsilon, true));
 
-}  // namespace
+// AlmostEqual with tuples
+static_assert(AlmostEqual(std::tie(kMeterZero), std::tie(kMeterZero)));
+static_assert(AlmostEqual(std::tie(kMeterZero, kMeterZero), std::tie(kMeterZero, kMeterZero)));
+static_assert(AlmostEqual(std::tie(kMeterZero, kMeterZero, kMeterZero), std::tie(kMeterZero, kMeterZero, kMeterZero)));
+
+static_assert(!AlmostEqual(std::tie(kMeterMax), std::tie(kMeterZero)));
+static_assert(!AlmostEqual(std::tie(kMeterZero, kMeterMax), std::tie(kMeterZero, kMeterZero)));
+static_assert(!AlmostEqual(std::tie(kMeterZero, kMeterZero, kMeterMax), std::tie(kMeterZero, kMeterZero, kMeterZero)));
+
+static_assert(AlmostEqual(std::tie(kMeterZero), std::tie(kMeterZero), kMeterCustomEpsilon, true));
+static_assert(AlmostEqual(std::tie(kMeterZero, kMeterZero), std::tie(kMeterZero, kMeterZero), kMeterCustomEpsilon, true));
+static_assert(AlmostEqual(std::tie(kMeterZero, kMeterZero, kMeterZero), std::tie(kMeterZero, kMeterZero, kMeterZero), kMeterCustomEpsilon, true));
+
+// AlmostEqual with tuples of different types
+static_assert(AlmostEqual(std::tie(kDoubleZero, kFloatZero, kMeterZero), std::tie(kDoubleZero, kFloatZero, kMeterZero)));
+static_assert(AlmostEqual(std::tie(kMeterZero, kDoubleZero, kFloatZero), std::tie(kMeterZero, kDoubleZero, kFloatZero), kDoubleCustomEpsilon));
+static_assert(AlmostEqual(std::tie(kFloatZero, kMeterZero, kDoubleZero), std::tie(kFloatZero, kMeterZero, kDoubleZero), kDoubleCustomEpsilon));
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Common/geometry_helper_test.cc b/test/MantleAPI/Common/geometry_helper_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..122e7647fdd4d7611f70a1cb17fe57826f27f540
--- /dev/null
+++ b/test/MantleAPI/Common/geometry_helper_test.cc
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <units.h>
+
+#include <vector>
+
+#include "MantleAPI/Common/i_geometry_helper.h"
+#include "MantleAPI/Common/mock_geometry_helper.h"
+#include "MantleAPI/Common/orientation.h"
+#include "MantleAPI/Common/vector.h"
+
+namespace mantle_api
+{
+
+using testing::_;
+using testing::Return;
+
+class GeometryHelperTest : public testing::Test
+{
+protected:
+  MockGeometryHelper mock_geometry_helper_;
+  IGeometryHelper& geometry_helper_{mock_geometry_helper_};
+};
+
+TEST_F(GeometryHelperTest, TranslateGlobalPositionLocally)
+{
+  static const auto kGlobalPosition = Vec3<units::length::meter_t>{};
+  static const auto kLocalOrientation = Orientation3<units::angle::radian_t>{};
+  static const auto kLocalTranslation = Vec3<units::length::meter_t>{};
+  static const auto kReturnValue = Vec3<units::length::meter_t>{};
+
+  EXPECT_CALL(mock_geometry_helper_, TranslateGlobalPositionLocally(_, _, _))
+      .Times(1)
+      .WillOnce(Return(kReturnValue));
+
+  std::ignore = geometry_helper_.TranslateGlobalPositionLocally(kGlobalPosition, kLocalOrientation, kLocalTranslation);
+}
+
+TEST_F(GeometryHelperTest, TransformPolylinePointsFromWorldToLocal)
+{
+  static const auto kPolylinePoints = std::vector<Vec3<units::length::meter_t>>{};
+  static const auto kLocalOrigin = Vec3<units::length::meter_t>{};
+  static const auto kLocalOrientation = Orientation3<units::angle::radian_t>{};
+  static const auto kReturnValue = std::vector<Vec3<units::length::meter_t>>{};
+
+  EXPECT_CALL(mock_geometry_helper_, TransformPolylinePointsFromWorldToLocal(_, _, _))
+      .Times(1)
+      .WillOnce(Return(kReturnValue));
+
+  std::ignore = geometry_helper_.TransformPolylinePointsFromWorldToLocal(kPolylinePoints, kLocalOrigin, kLocalOrientation);
+}
+
+TEST_F(GeometryHelperTest, TransformPositionFromWorldToLocal)
+{
+  static const auto kWorldPosition = Vec3<units::length::meter_t>{};
+  static const auto kLocalOrigin = Vec3<units::length::meter_t>{};
+  static const auto kLocalOrientation = Orientation3<units::angle::radian_t>{};
+  static const auto kReturnValue = Vec3<units::length::meter_t>{};
+
+  EXPECT_CALL(mock_geometry_helper_, TransformPositionFromWorldToLocal(_, _, _))
+      .Times(1)
+      .WillOnce(Return(kReturnValue));
+
+  std::ignore = geometry_helper_.TransformPositionFromWorldToLocal(kWorldPosition, kLocalOrigin, kLocalOrientation);
+}
+
+TEST_F(GeometryHelperTest, AreOrientedSimilarly)
+{
+  static const auto kOrientation1 = Orientation3<units::angle::radian_t>{};
+  static const auto kOrientation2 = Orientation3<units::angle::radian_t>{};
+  static const auto kReturnValue = true;
+
+  EXPECT_CALL(mock_geometry_helper_, AreOrientedSimilarly(_, _))
+      .Times(1)
+      .WillOnce(Return(kReturnValue));
+
+  std::ignore = geometry_helper_.AreOrientedSimilarly(kOrientation1, kOrientation2);
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Common/identifiable_test.cc b/test/MantleAPI/Common/identifiable_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b36cdf06fded47cc7169f171b7a55b30944b7370
--- /dev/null
+++ b/test/MantleAPI/Common/identifiable_test.cc
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2023, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <string>
+#include <tuple>
+#include <utility>
+
+#include "MantleAPI/Common/i_identifiable.h"
+#include "MantleAPI/Common/mock_identifiable.h"
+
+namespace mantle_api
+{
+
+using testing::_;
+using testing::Return;
+using testing::ReturnRef;
+
+class IdentifiableTest : public testing::Test
+{
+protected:
+  MockIdentifiable mock_identifiable_;
+  IIdentifiable& identifiable_{mock_identifiable_};
+};
+
+TEST_F(IdentifiableTest, GetUniqueId)
+{
+  EXPECT_CALL(std::as_const(mock_identifiable_), GetUniqueId())
+      .Times(1)
+      .WillOnce(Return(UniqueId{}));
+
+  std::ignore = std::as_const(identifiable_).GetUniqueId();
+}
+
+TEST_F(IdentifiableTest, SetName)
+{
+  EXPECT_CALL(mock_identifiable_, SetName(_))
+      .Times(1);
+
+  identifiable_.SetName({});
+}
+
+TEST_F(IdentifiableTest, GetName)
+{
+  const auto default_string = std::string{"default_string"};
+
+  EXPECT_CALL(std::as_const(mock_identifiable_), GetName())
+      .Times(1)
+      .WillOnce(ReturnRef(default_string));
+
+  std::ignore = std::as_const(identifiable_).GetName();
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Common/identifier_test.cc b/test/MantleAPI/Common/identifier_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1a664260e73ef4f2922c0b19bffa8a30b6928d41
--- /dev/null
+++ b/test/MantleAPI/Common/identifier_test.cc
@@ -0,0 +1,342 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include "MantleAPI/Common/identifier.h"
+
+#include <gtest/gtest.h>
+
+#include <cstdint>
+#include <functional>
+#include <sstream>
+#include <type_traits>
+#include <utility>
+
+namespace mantle_api
+{
+
+using TestIdentifier = Identifier<std::uint64_t, struct TestIdentifierTag>;
+
+static_assert(std::is_nothrow_default_constructible_v<TestIdentifier>);
+static_assert(std::is_nothrow_constructible_v<TestIdentifier, TestIdentifier::ValueType>);
+static_assert(std::is_nothrow_copy_constructible_v<TestIdentifier>);
+static_assert(std::is_nothrow_move_constructible_v<TestIdentifier>);
+static_assert(std::is_nothrow_copy_assignable_v<TestIdentifier>);
+static_assert(std::is_nothrow_move_assignable_v<TestIdentifier>);
+static_assert(std::is_nothrow_destructible_v<TestIdentifier>);
+static_assert(std::is_nothrow_swappable_v<TestIdentifier>);
+
+TEST(IdentifierTest, DefaultConstruction)
+{
+  constexpr auto id = TestIdentifier{};
+
+  EXPECT_EQ(id, TestIdentifier::kInvalid);
+
+  static_assert(id == TestIdentifier::kInvalid);
+}
+
+TEST(IdentifierTest, Construction)
+{
+  constexpr auto id = TestIdentifier{1};
+
+  EXPECT_EQ(id, 1);
+
+  static_assert(id == 1);
+}
+
+TEST(IdentifierTest, CopyConstruction)
+{
+  constexpr auto id1 = TestIdentifier{1};
+  constexpr auto id2 = TestIdentifier{id1};
+
+  EXPECT_EQ(id2, id1);
+
+  static_assert(id2 == id1);
+}
+
+TEST(IdentifierTest, MoveConstruction)
+{
+  auto id1 = TestIdentifier{1};
+  const auto id2 = TestIdentifier{std::move(id1)};
+
+  EXPECT_EQ(id1, TestIdentifier::kInvalid);  // NOLINT(bugprone-use-after-move)
+  EXPECT_EQ(id2, 1);
+}
+
+TEST(IdentifierTest, CopyAssignment)
+{
+  const auto id1 = TestIdentifier{1};
+  const auto id2 = id1;
+
+  EXPECT_EQ(id1, 1);
+  EXPECT_EQ(id2, 1);
+}
+
+TEST(IdentifierTest, NonConstCopyAssignment)
+{
+  auto id1 = TestIdentifier{1};
+  auto id2 = id1;
+
+  EXPECT_EQ(id1, 1);
+  EXPECT_EQ(id2, 1);
+}
+
+TEST(IdentifierTest, MoveAssignment)
+{
+  auto id1 = TestIdentifier{1};
+  auto id2 = TestIdentifier{2};
+  id2 = std::move(id1);
+
+  EXPECT_EQ(id1, TestIdentifier::kInvalid);  // NOLINT(bugprone-use-after-move)
+  EXPECT_EQ(id2, 1);
+}
+
+TEST(IdentifierTest, Value)
+{
+  constexpr auto id = TestIdentifier{1};
+  constexpr auto value = id.Value();
+
+  EXPECT_EQ(id, value);
+
+  static_assert(id == value);
+}
+
+TEST(IdentifierTest, ConversionOperator)
+{
+  constexpr auto id = TestIdentifier{1};
+  constexpr auto value = static_cast<TestIdentifier::ValueType>(id);
+
+  EXPECT_EQ(id.Value(), value);
+
+  static_assert(id.Value() == value);
+}
+
+TEST(IdentifierTest, HasValue)
+{
+  constexpr auto id = TestIdentifier{1};
+  constexpr auto has_value = id.HasValue();
+
+  EXPECT_TRUE(has_value);
+  EXPECT_TRUE(id);
+
+  static_assert(has_value);
+  static_assert(id);
+}
+
+TEST(IdentifierTest, HasNoValue)
+{
+  constexpr auto id = TestIdentifier{};
+  constexpr auto has_value = id.HasValue();
+
+  EXPECT_FALSE(has_value);
+  EXPECT_FALSE(id);
+
+  static_assert(!has_value);
+  static_assert(!id);
+}
+
+TEST(IdentifierTest, AssignmentOperatorValueType)
+{
+  auto id = TestIdentifier{};
+  id = 1;
+
+  EXPECT_EQ(id, 1);
+}
+
+TEST(IdentifierTest, OperatorEqual)
+{
+  constexpr auto lhs = TestIdentifier{1};
+  constexpr auto rhs = TestIdentifier{1};
+
+  EXPECT_EQ(lhs, rhs);
+
+  static_assert(lhs == rhs);
+}
+
+TEST(IdentifierTest, OperatorNotEqual)
+{
+  constexpr auto lhs = TestIdentifier{1};
+  constexpr auto rhs = TestIdentifier{2};
+
+  EXPECT_NE(lhs, rhs);
+
+  static_assert(lhs != rhs);
+}
+
+TEST(IdentifierTest, OperatorEqualValueType)
+{
+  constexpr auto lhs = TestIdentifier{1};
+  constexpr auto rhs = TestIdentifier{1};
+
+  EXPECT_EQ(lhs, rhs.Value());
+  EXPECT_EQ(lhs.Value(), rhs);
+
+  static_assert(lhs == rhs.Value());
+  static_assert(lhs.Value() == rhs);
+}
+
+TEST(IdentifierTest, OperatorNotEqualValueType)
+{
+  constexpr auto lhs = TestIdentifier{1};
+  constexpr auto rhs = TestIdentifier{2};
+
+  EXPECT_NE(lhs, rhs.Value());
+  EXPECT_NE(lhs.Value(), rhs);
+
+  static_assert(lhs != rhs.Value());
+  static_assert(lhs.Value() != rhs);
+}
+
+TEST(IdentifierTest, OperatorLessThan)
+{
+  constexpr auto lhs = TestIdentifier{1};
+  constexpr auto rhs = TestIdentifier{2};
+
+  EXPECT_LT(lhs, rhs);
+
+  static_assert(lhs < rhs);
+}
+
+TEST(IdentifierTest, OperatorLessThanWithValueType)
+{
+  constexpr auto lhs = TestIdentifier{1};
+  constexpr auto rhs = TestIdentifier{2};
+
+  EXPECT_LT(lhs, rhs.Value());
+
+  static_assert(lhs < rhs.Value());
+}
+
+TEST(IdentifierTest, OperatorGreaterThan)
+{
+  constexpr auto lhs = TestIdentifier{2};
+  constexpr auto rhs = TestIdentifier{1};
+
+  EXPECT_GT(lhs, rhs);
+
+  static_assert(lhs > rhs);
+}
+
+TEST(IdentifierTest, OperatorGreaterThanWithValueType)
+{
+  constexpr auto lhs = TestIdentifier{2};
+  constexpr auto rhs = TestIdentifier{1};
+
+  EXPECT_GT(lhs, rhs.Value());
+
+  static_assert(lhs > rhs.Value());
+}
+
+TEST(IdentifierTest, OperatorLessOrEqual)
+{
+  constexpr auto lhs = TestIdentifier{1};
+  constexpr auto rhs = TestIdentifier{1};
+  constexpr auto rhs_2 = TestIdentifier{2};
+
+  EXPECT_LE(lhs, rhs);
+  EXPECT_LE(lhs, rhs_2);
+
+  static_assert(lhs <= rhs);
+  static_assert(lhs <= rhs_2);
+}
+
+TEST(IdentifierTest, OperatorLessOrEqualWithValueType)
+{
+  constexpr auto lhs = TestIdentifier{1};
+  constexpr auto rhs = TestIdentifier{1};
+  constexpr auto rhs_2 = TestIdentifier{2};
+
+  EXPECT_LE(lhs, rhs.Value());
+  EXPECT_LE(lhs, rhs_2.Value());
+
+  static_assert(lhs <= rhs.Value());
+  static_assert(lhs <= rhs_2.Value());
+}
+
+TEST(IdentifierTest, OperatorGreaterOrEqual)
+{
+  constexpr auto lhs = TestIdentifier{2};
+  constexpr auto rhs = TestIdentifier{2};
+  constexpr auto rhs_2 = TestIdentifier{1};
+
+  EXPECT_GE(lhs, rhs);
+  EXPECT_GE(lhs, rhs_2);
+
+  static_assert(lhs >= rhs);
+  static_assert(lhs >= rhs_2);
+}
+
+TEST(IdentifierTest, OperatorGreaterOrEqualWithValueType)
+{
+  constexpr auto lhs = TestIdentifier{2};
+  constexpr auto rhs = TestIdentifier{2};
+  constexpr auto rhs_2 = TestIdentifier{1};
+
+  EXPECT_GE(lhs, rhs.Value());
+  EXPECT_GE(lhs, rhs_2.Value());
+
+  static_assert(lhs >= rhs.Value());
+  static_assert(lhs >= rhs_2.Value());
+}
+
+TEST(IdentifierTest, PrefixIncrement)
+{
+  auto id = TestIdentifier{1};
+
+  EXPECT_EQ(++id, 2);
+}
+
+TEST(IdentifierTest, PostfixIncrement)
+{
+  auto id = TestIdentifier{1};
+
+  EXPECT_EQ(id++, 1);
+  EXPECT_EQ(id, 2);
+}
+
+TEST(IdentifierTest, Add)
+{
+  constexpr auto id1 = TestIdentifier{1};
+  constexpr auto id2 = TestIdentifier{1};
+
+  const auto id3 = id1 + id2;
+
+  EXPECT_EQ(id3, 2);
+}
+
+TEST(IdentifierTest, Swap)
+{
+  auto id1 = TestIdentifier{1};
+  auto id2 = TestIdentifier{2};
+
+  std::swap(id1, id2);
+
+  EXPECT_EQ(id1, 2);
+  EXPECT_EQ(id2, 1);
+}
+
+TEST(IdentifierTest, OutputStreamOperator)
+{
+  constexpr auto id = TestIdentifier{1};
+
+  std::ostringstream oss;
+  oss << id;
+
+  EXPECT_STREQ(oss.str().c_str(), "1");
+}
+
+TEST(IdentifierTest, Hash)
+{
+  constexpr auto id = TestIdentifier{1};
+  const auto hash = std::hash<TestIdentifier>{}(id);
+
+  EXPECT_EQ(hash, std::hash<TestIdentifier::ValueType>{}(id.Value()));
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Common/log_utils_test.cc b/test/MantleAPI/Common/log_utils_test.cc
deleted file mode 100644
index 7a376fa284a39c1f7a542aae7def849bf72f7e58..0000000000000000000000000000000000000000
--- a/test/MantleAPI/Common/log_utils_test.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2023, Mercedes-Benz Tech Innovation GmbH
- *
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- *******************************************************************************/
-
-#include "MantleAPI/Common/log_utils.h"
-
-#include <gtest/gtest.h>
-
-#include <limits>
-#include <sstream>
-#include <type_traits>
-
-#include "MantleAPI/Common/i_logger.h"
-
-namespace
-{
-
-using mantle_api::LogLevel;
-using mantle_api::log_utils::ToStringView;
-
-static_assert(ToStringView(LogLevel::kTrace) == "Trace");
-static_assert(ToStringView(LogLevel::kDebug) == "Debug");
-static_assert(ToStringView(LogLevel::kInfo) == "Info");
-static_assert(ToStringView(LogLevel::kWarning) == "Warning");
-static_assert(ToStringView(LogLevel::kError) == "Error");
-static_assert(ToStringView(LogLevel::kCritical) == "Critical");
-
-TEST(LogUtilsTest, ToStringView)
-{
-  ASSERT_STREQ(ToStringView(LogLevel::kTrace).data(), "Trace");
-  ASSERT_STREQ(ToStringView(LogLevel::kDebug).data(), "Debug");
-  ASSERT_STREQ(ToStringView(LogLevel::kInfo).data(), "Info");
-  ASSERT_STREQ(ToStringView(LogLevel::kWarning).data(), "Warning");
-  ASSERT_STREQ(ToStringView(LogLevel::kError).data(), "Error");
-  ASSERT_STREQ(ToStringView(LogLevel::kCritical).data(), "Critical");
-
-  ASSERT_STREQ(ToStringView(static_cast<LogLevel>(std::numeric_limits<std::underlying_type_t<LogLevel>>::min())).data(), "Log level out of range");
-  ASSERT_STREQ(ToStringView(static_cast<LogLevel>(std::numeric_limits<std::underlying_type_t<LogLevel>>::max())).data(), "Log level out of range");
-}
-
-TEST(LogUtilsTest, OutputStreamOperator)
-{
-  {
-    auto stream = std::ostringstream{};
-    ASSERT_NO_THROW(stream << LogLevel::kTrace);
-    ASSERT_STREQ(stream.str().c_str(), "Trace");
-  }
-  {
-    auto stream = std::ostringstream{};
-    ASSERT_NO_THROW(stream << LogLevel::kDebug);
-    ASSERT_STREQ(stream.str().c_str(), "Debug");
-  }
-  {
-    auto stream = std::ostringstream{};
-    ASSERT_NO_THROW(stream << LogLevel::kInfo);
-    ASSERT_STREQ(stream.str().c_str(), "Info");
-  }
-  {
-    auto stream = std::ostringstream{};
-    ASSERT_NO_THROW(stream << LogLevel::kWarning);
-    ASSERT_STREQ(stream.str().c_str(), "Warning");
-  }
-  {
-    auto stream = std::ostringstream{};
-    ASSERT_NO_THROW(stream << LogLevel::kError);
-    ASSERT_STREQ(stream.str().c_str(), "Error");
-  }
-  {
-    auto stream = std::ostringstream{};
-    ASSERT_NO_THROW(stream << LogLevel::kCritical);
-    ASSERT_STREQ(stream.str().c_str(), "Critical");
-  }
-}
-
-}  // namespace
diff --git a/test/MantleAPI/Common/logger_test.cc b/test/MantleAPI/Common/logger_test.cc
index d9f780ae4a20de23c46845c7dad0af222ad816a1..62402add9500a108a357b468b3d58e456b46a504 100644
--- a/test/MantleAPI/Common/logger_test.cc
+++ b/test/MantleAPI/Common/logger_test.cc
@@ -11,15 +11,16 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include <utility>
+
 #include "MantleAPI/Common/i_logger.h"
+#include "MantleAPI/Common/meta.h"
 #include "MantleAPI/Common/mock_logger.h"
 
-namespace
+namespace mantle_api
 {
 
-using mantle_api::LogLevel;
 using testing::_;
-using testing::Const;
 using testing::Return;
 
 class LoggerTest : public testing::Test
@@ -30,16 +31,16 @@ protected:
     mock_logger_.DelegateToFake();
   }
 
-  mantle_api::MockLogger mock_logger_;
-  mantle_api::ILogger &logger_{mock_logger_};
+  MockLogger mock_logger_;
+  ILogger &logger_{mock_logger_};
 };
 
 TEST_F(LoggerTest, GetCurrentLogLevel)
 {
-  EXPECT_CALL(Const(mock_logger_), GetCurrentLogLevel())  //
-      .Times(1)                                           //
+  EXPECT_CALL(std::as_const(mock_logger_), GetCurrentLogLevel())
+      .Times(1)
       .WillRepeatedly(Return(LogLevel::kTrace));
-  ASSERT_NO_THROW(std::ignore = logger_.GetCurrentLogLevel());
+  ASSERT_NO_THROW(std::ignore = std::as_const(logger_).GetCurrentLogLevel());
 }
 
 TEST_F(LoggerTest, Log)
@@ -84,4 +85,14 @@ TEST_F(LoggerTest, Critical)
   ASSERT_NO_THROW(logger_.Critical("LoggerTest_Critical"));
 }
 
-}  // namespace
+TEST_F(LoggerTest, LogLevel)
+{
+  static_assert(meta::enum_to_string(LogLevel::kTrace) == "Trace");
+  static_assert(meta::enum_to_string(LogLevel::kDebug) == "Debug");
+  static_assert(meta::enum_to_string(LogLevel::kInfo) == "Info");
+  static_assert(meta::enum_to_string(LogLevel::kWarning) == "Warning");
+  static_assert(meta::enum_to_string(LogLevel::kError) == "Error");
+  static_assert(meta::enum_to_string(LogLevel::kCritical) == "Critical");
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Common/meta_test.cc b/test/MantleAPI/Common/meta_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c29235547fbb3e1b881b021b6c6b1de197494cd1
--- /dev/null
+++ b/test/MantleAPI/Common/meta_test.cc
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include "MantleAPI/Common/meta.h"
+
+#include <gtest/gtest.h>
+
+#include <array>
+#include <cstdint>
+#include <sstream>
+
+namespace mantle_api
+{
+
+inline constexpr auto kEnumSize = 3U;
+
+enum class EnumUnsigned : std::uint8_t
+{
+  k1st = 0,
+  k2nd,
+  k3rd
+};
+
+template <>
+struct meta::info<EnumUnsigned>
+{
+  [[nodiscard]] static constexpr std::array<enum_info<EnumUnsigned>, kEnumSize> get_enumerators() noexcept
+  {
+    return {{{EnumUnsigned::k1st, "1st"},
+             {EnumUnsigned::k2nd, "2nd"},
+             {EnumUnsigned::k3rd, "3rd"}}};
+  }
+};
+
+enum class EnumSigned : std::int8_t
+{
+  k1st = -1,
+  k2nd,
+  k3rd
+};
+
+template <>
+struct meta::info<EnumSigned>
+{
+  [[nodiscard]] static constexpr std::array<enum_info<EnumSigned>, kEnumSize> get_enumerators() noexcept
+  {
+    return {{{EnumSigned::k1st, "1st"},
+             {EnumSigned::k2nd, "2nd"},
+             {EnumSigned::k3rd, "3rd"}}};
+  }
+};
+
+template <typename T>
+class MetaTest : public testing::Test
+{
+};
+
+using EnumTypes = ::testing::Types<EnumUnsigned, EnumSigned>;
+TYPED_TEST_SUITE(MetaTest, EnumTypes);
+
+TYPED_TEST(MetaTest, ValueOf)
+{
+  constexpr auto enumerators = meta::enumerators_of(TypeParam{});
+  static_assert(meta::value_of(enumerators[0]) == TypeParam::k1st);
+  static_assert(meta::value_of(enumerators[1]) == TypeParam::k2nd);
+  static_assert(meta::value_of(enumerators[2]) == TypeParam::k3rd);
+}
+
+TYPED_TEST(MetaTest, NameOf)
+{
+  constexpr auto enumerators = meta::enumerators_of(TypeParam{});
+  static_assert(meta::name_of(enumerators[0]) == "1st");
+  static_assert(meta::name_of(enumerators[1]) == "2nd");
+  static_assert(meta::name_of(enumerators[2]) == "3rd");
+}
+
+TYPED_TEST(MetaTest, EnumeratorsOf)
+{
+  {
+    constexpr auto enumerators = meta::enumerators_of(TypeParam{});
+    static_assert(enumerators.size() == kEnumSize);
+  }
+  {
+    constexpr auto enumerators = meta::enumerators_of<TypeParam>();
+    static_assert(enumerators.size() == kEnumSize);
+  }
+}
+
+TYPED_TEST(MetaTest, SizeOf)
+{
+  static_assert(meta::size_of(TypeParam{}) == kEnumSize);
+  static_assert(meta::size_of<TypeParam>() == kEnumSize);
+}
+
+TYPED_TEST(MetaTest, EnumToString)
+{
+  static_assert(meta::enum_to_string(TypeParam::k1st) == "1st");
+  static_assert(meta::enum_to_string(TypeParam::k2nd) == "2nd");
+  static_assert(meta::enum_to_string(TypeParam::k3rd) == "3rd");
+}
+
+TYPED_TEST(MetaTest, EnumToStringOutOfRange)
+{
+  static_assert(meta::enum_to_string(static_cast<TypeParam>(-10)).empty());
+  static_assert(meta::enum_to_string(static_cast<TypeParam>(10)).empty());
+}
+
+TYPED_TEST(MetaTest, StringToEnum)
+{
+  static_assert(meta::string_to_enum<TypeParam>("1st") == TypeParam::k1st);
+  static_assert(meta::string_to_enum<TypeParam>("2nd") == TypeParam::k2nd);
+  static_assert(meta::string_to_enum<TypeParam>("3rd") == TypeParam::k3rd);
+}
+
+TYPED_TEST(MetaTest, StringToEnumUndefined)
+{
+  static_assert(!meta::string_to_enum<TypeParam>("Undef"));
+}
+
+TYPED_TEST(MetaTest, StringToEnumEmpty)
+{
+  static_assert(!meta::string_to_enum<TypeParam>(""));
+}
+
+TYPED_TEST(MetaTest, OutputStreamOperator)
+{
+  std::ostringstream oss;
+
+  oss << TypeParam::k1st;
+  EXPECT_EQ(oss.str(), "1st");
+
+  oss.str("");
+  oss << TypeParam::k2nd;
+  EXPECT_EQ(oss.str(), "2nd");
+
+  oss.str("");
+  oss << TypeParam::k3rd;
+  EXPECT_EQ(oss.str(), "3rd");
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Common/mock_geometry_helper.h b/test/MantleAPI/Common/mock_geometry_helper.h
new file mode 100644
index 0000000000000000000000000000000000000000..343c4e3ad1a5aea417878061d37c6c9401b71f33
--- /dev/null
+++ b/test/MantleAPI/Common/mock_geometry_helper.h
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2023, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#ifndef MANTLEAPI_COMMON_MOCK_GEOMETRY_HELPER_H
+#define MANTLEAPI_COMMON_MOCK_GEOMETRY_HELPER_H
+
+#include <gmock/gmock.h>
+#include <units.h>
+
+#include "MantleAPI/Common/i_geometry_helper.h"
+#include "MantleAPI/Common/orientation.h"
+#include "MantleAPI/Common/vector.h"
+
+namespace mantle_api
+{
+
+class MockGeometryHelper : public IGeometryHelper
+{
+public:
+  MOCK_METHOD(Vec3<units::length::meter_t>, TranslateGlobalPositionLocally, (const Vec3<units::length::meter_t>& global_position, const Orientation3<units::angle::radian_t>& local_orientation, const Vec3<units::length::meter_t>& local_translation), (const, override));
+  MOCK_METHOD(std::vector<Vec3<units::length::meter_t>>, TransformPolylinePointsFromWorldToLocal, (const std::vector<Vec3<units::length::meter_t>>& polyline_points, const Vec3<units::length::meter_t>& local_origin, const Orientation3<units::angle::radian_t>& local_orientation), (const, override));
+  MOCK_METHOD(Vec3<units::length::meter_t>, TransformPositionFromWorldToLocal, (const Vec3<units::length::meter_t>& world_position, const Vec3<units::length::meter_t>& local_origin, const Orientation3<units::angle::radian_t>& local_orientation), (const, override));
+  MOCK_METHOD(bool, AreOrientedSimilarly, (const Orientation3<units::angle::radian_t>& orientation1, const Orientation3<units::angle::radian_t>& orientation2), (const, override));
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_COMMON_MOCK_GEOMETRY_HELPER_H
diff --git a/test/MantleAPI/Common/mock_identifiable.h b/test/MantleAPI/Common/mock_identifiable.h
new file mode 100644
index 0000000000000000000000000000000000000000..f5e243cb075897221b9cd804341905e879320329
--- /dev/null
+++ b/test/MantleAPI/Common/mock_identifiable.h
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2023, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#ifndef MANTLEAPI_COMMON_MOCK_IDENTIFIABLE_H
+#define MANTLEAPI_COMMON_MOCK_IDENTIFIABLE_H
+
+#include <gmock/gmock.h>
+
+#include "MantleAPI/Common/i_identifiable.h"
+
+namespace mantle_api
+{
+
+class MockIdentifiable : public IIdentifiable
+{
+public:
+  MOCK_METHOD(UniqueId, GetUniqueId, (), (const, override));
+  MOCK_METHOD(void, SetName, (const std::string& name), (override));
+  MOCK_METHOD(const std::string&, GetName, (), (const, override));
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_COMMON_MOCK_IDENTIFIABLE_H
diff --git a/test/MantleAPI/Common/mock_logger.h b/test/MantleAPI/Common/mock_logger.h
index 44e2b22ad6551dcfaf0e323b1257d3d3041b1e66..f9785248fd34e12dc227dc0c0f79c6b8def74f00 100644
--- a/test/MantleAPI/Common/mock_logger.h
+++ b/test/MantleAPI/Common/mock_logger.h
@@ -17,12 +17,11 @@
 #include <ostream>
 
 #include "MantleAPI/Common/i_logger.h"
-#include "MantleAPI/Common/log_utils.h"
 
 namespace mantle_api
 {
 
-class MockLogger final : public ILogger
+class MockLogger : public ILogger
 {
 public:
   MOCK_METHOD(LogLevel, GetCurrentLogLevel, (), (const, noexcept, override));
@@ -33,7 +32,7 @@ public:
     auto print = [](LogLevel level, std::string_view message)
     { std::cout
           << "["
-          << level  // use the ostream operator from log_utils
+          << level
           << "] "
           << std::quoted(message)
           << '\n'; };
diff --git a/test/MantleAPI/Common/orientation_test.cc b/test/MantleAPI/Common/orientation_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b2b846df741dd0774d8cbe2631d952635f6feb7a
--- /dev/null
+++ b/test/MantleAPI/Common/orientation_test.cc
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include "MantleAPI/Common/orientation.h"
+
+#include <gtest/gtest.h>
+#include <units.h>
+
+#include <sstream>
+#include <type_traits>
+
+namespace mantle_api
+{
+
+using ::units::literals::operator""_rad;
+using Orientation3RadianType = Orientation3<units::angle::radian_t>;
+
+static_assert(std::is_trivial_v<Orientation3RadianType>);
+
+TEST(Orientation3Test, OperatorEqual)
+{
+  constexpr const auto lhs = Orientation3RadianType{1_rad, 1_rad, 1_rad};
+  constexpr const auto rhs = Orientation3RadianType{1_rad, 1_rad, 1_rad};
+
+  ASSERT_EQ(lhs, rhs);
+
+  static_assert(lhs == rhs);
+}
+
+TEST(Orientation3Test, OperatorNotEqual)
+{
+  constexpr const auto lhs = Orientation3RadianType{1_rad, 1_rad, 1_rad};
+  constexpr const auto rhs = Orientation3RadianType{2_rad, 2_rad, 2_rad};
+
+  ASSERT_NE(lhs, rhs);
+
+  static_assert(lhs != rhs);
+}
+
+TEST(Orientation3Test, Add)
+{
+  constexpr const auto lhs = Orientation3RadianType{1_rad, 1_rad, 1_rad};
+  constexpr const auto rhs = Orientation3RadianType{1_rad, 1_rad, 1_rad};
+  constexpr const auto expected_result = Orientation3RadianType{2_rad, 2_rad, 2_rad};
+
+  constexpr const auto result = lhs + rhs;
+
+  ASSERT_EQ(result, expected_result);
+
+  static_assert(result == expected_result);
+}
+
+TEST(Orientation3Test, Subtract)
+{
+  constexpr const auto lhs = Orientation3RadianType{2_rad, 2_rad, 2_rad};
+  constexpr const auto rhs = Orientation3RadianType{1_rad, 1_rad, 1_rad};
+  constexpr const auto expected_result = Orientation3RadianType{1_rad, 1_rad, 1_rad};
+
+  constexpr const auto result = lhs - rhs;
+
+  ASSERT_EQ(result, expected_result);
+
+  static_assert(result == expected_result);
+}
+
+TEST(Orientation3Test, OutputStreamOperator)
+{
+  const auto orientation = Orientation3RadianType{1_rad, 1_rad, 1_rad};
+
+  auto oss = std::ostringstream{};
+  oss << orientation;
+
+  ASSERT_EQ(oss.str(), "Orientation3(.yaw=1 rad, .pitch=1 rad, .roll=1 rad)");
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Common/poly_line_test.cc b/test/MantleAPI/Common/poly_line_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ed17aede97ef0633cd8ec52f8acfcaf372a4d34c
--- /dev/null
+++ b/test/MantleAPI/Common/poly_line_test.cc
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include "MantleAPI/Common/poly_line.h"
+
+#include <gtest/gtest.h>
+#include <units.h>
+
+#include <sstream>
+#include <type_traits>
+
+namespace mantle_api
+{
+
+using ::units::literals::operator""_m;
+using ::units::literals::operator""_rad;
+using ::units::literals::operator""_s;
+
+static_assert(std::is_aggregate_v<PolyLinePoint>);
+
+TEST(PolyLinePoint, OperatorEqual)
+{
+  constexpr const auto lhs = PolyLinePoint{{{1_m, 1_m, 1_m}, {1_rad, 1_rad, 1_rad}}, 1_s};
+  constexpr const auto rhs = PolyLinePoint{{{1_m, 1_m, 1_m}, {1_rad, 1_rad, 1_rad}}, 1_s};
+
+  ASSERT_EQ(lhs, rhs);
+
+  static_assert(lhs == rhs);
+}
+
+TEST(PolyLinePoint, OperatorNotEqual)
+{
+  constexpr const auto lhs = PolyLinePoint{{{1_m, 1_m, 1_m}, {1_rad, 1_rad, 1_rad}}, 1_s};
+  constexpr const auto rhs = PolyLinePoint{{{2_m, 2_m, 2_m}, {2_rad, 2_rad, 2_rad}}, 2_s};
+
+  ASSERT_NE(lhs, rhs);
+
+  static_assert(lhs != rhs);
+}
+
+TEST(PolyLinePoint, OutputStreamOperatorNoTime)
+{
+  const auto poly_line_point = PolyLinePoint{{{1_m, 1_m, 1_m}, {1_rad, 1_rad, 1_rad}}, std::nullopt};
+
+  auto oss = std::ostringstream{};
+  oss << poly_line_point;
+
+  ASSERT_EQ(oss.str(), "PolyLinePoint(.pose=Pose(.position=Vec3(.x=1 m, .y=1 m, .z=1 m), .orientation=Orientation3(.yaw=1 rad, .pitch=1 rad, .roll=1 rad)), .time=0 s)");
+}
+
+TEST(PolyLinePoint, OutputStreamOperator)
+{
+  const auto poly_line_point = PolyLinePoint{{{1_m, 1_m, 1_m}, {1_rad, 1_rad, 1_rad}}, 1_s};
+
+  auto oss = std::ostringstream{};
+  oss << poly_line_point;
+
+  ASSERT_EQ(oss.str(), "PolyLinePoint(.pose=Pose(.position=Vec3(.x=1 m, .y=1 m, .z=1 m), .orientation=Orientation3(.yaw=1 rad, .pitch=1 rad, .roll=1 rad)), .time=1 s)");
+}
+
+TEST(PolyLine, OutputStreamOperatorEmpty)
+{
+  const auto poly_line = PolyLine{};
+
+  auto oss = std::ostringstream{};
+  oss << poly_line;
+
+  ASSERT_EQ(oss.str(), "PolyLine()");
+}
+
+TEST(PolyLine, OutputStreamOperatorOnePoint)
+{
+  const auto poly_line = PolyLine{
+      {{{1_m, 1_m, 1_m}, {1_rad, 1_rad, 1_rad}}, 1_s},
+  };
+
+  auto oss = std::ostringstream{};
+  oss << poly_line;
+
+  ASSERT_EQ(oss.str(), "PolyLine([0]=PolyLinePoint(.pose=Pose(.position=Vec3(.x=1 m, .y=1 m, .z=1 m), .orientation=Orientation3(.yaw=1 rad, .pitch=1 rad, .roll=1 rad)), .time=1 s))");
+}
+
+TEST(PolyLine, OutputStreamOperator)
+{
+  const auto poly_line = PolyLine{
+      {{{1_m, 1_m, 1_m}, {1_rad, 1_rad, 1_rad}}, 1_s},
+      {{{2_m, 2_m, 2_m}, {2_rad, 2_rad, 2_rad}}, 2_s}};
+
+  auto oss = std::ostringstream{};
+  oss << poly_line;
+
+  ASSERT_EQ(oss.str(),
+            "PolyLine([0]=PolyLinePoint(.pose=Pose(.position=Vec3(.x=1 m, .y=1 m, .z=1 m), .orientation=Orientation3(.yaw=1 rad, .pitch=1 rad, .roll=1 rad)), .time=1 s), [1]=PolyLinePoint(.pose=Pose(.position=Vec3(.x=2 m, .y=2 m, .z=2 m), .orientation=Orientation3(.yaw=2 rad, .pitch=2 rad, .roll=2 rad)), .time=2 s))");
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Common/pose_test.cc b/test/MantleAPI/Common/pose_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d80ead27cc860d8ee137a4e65eaa637d9a010a0f
--- /dev/null
+++ b/test/MantleAPI/Common/pose_test.cc
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include "MantleAPI/Common/pose.h"
+
+#include <gtest/gtest.h>
+#include <units.h>
+
+#include <sstream>
+#include <type_traits>
+
+namespace mantle_api
+{
+
+using ::units::literals::operator""_m;
+using ::units::literals::operator""_rad;
+
+static_assert(std::is_trivial_v<Pose>);
+
+TEST(PoseTest, OperatorEqual)
+{
+  constexpr const auto lhs = Pose{{1_m, 1_m, 1_m}, {1_rad, 1_rad, 1_rad}};
+  constexpr const auto rhs = Pose{{1_m, 1_m, 1_m}, {1_rad, 1_rad, 1_rad}};
+
+  ASSERT_EQ(lhs, rhs);
+
+  static_assert(lhs == rhs);
+}
+
+TEST(PoseTest, OperatorNotEqual)
+{
+  constexpr const auto lhs = Pose{{1_m, 1_m, 1_m}, {1_rad, 1_rad, 1_rad}};
+  constexpr const auto rhs = Pose{{2_m, 2_m, 2_m}, {2_rad, 2_rad, 2_rad}};
+
+  ASSERT_NE(lhs, rhs);
+
+  static_assert(lhs != rhs);
+}
+
+TEST(PoseTest, OutputStreamOperator)
+{
+  const auto pose = Pose{{1_m, 1_m, 1_m}, {1_rad, 1_rad, 1_rad}};
+
+  auto oss = std::ostringstream{};
+  oss << pose;
+
+  ASSERT_EQ(oss.str(), "Pose(.position=Vec3(.x=1 m, .y=1 m, .z=1 m), .orientation=Orientation3(.yaw=1 rad, .pitch=1 rad, .roll=1 rad))");
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Common/position_test.cc b/test/MantleAPI/Common/position_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5436c8d8248759ada74389554ac3cc210ef8c471
--- /dev/null
+++ b/test/MantleAPI/Common/position_test.cc
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include "MantleAPI/Common/position.h"
+
+#include <gtest/gtest.h>
+#include <units.h>
+
+#include <sstream>
+#include <type_traits>
+
+namespace mantle_api
+{
+
+using ::units::literals::operator""_m;
+using ::units::literals::operator""_rad;
+
+/*******************************************************************************
+ * OpenDriveRoadPosition
+ *******************************************************************************/
+static_assert(std::is_aggregate_v<OpenDriveRoadPosition>);
+
+TEST(OpenDriveRoadPositionTest, OperatorEqual)
+{
+  auto lhs = OpenDriveRoadPosition{"Road1", 1_m, 1_m};
+  auto rhs = OpenDriveRoadPosition{"Road1", 1_m, 1_m};
+
+  ASSERT_EQ(lhs, rhs);
+}
+
+TEST(OpenDriveRoadPositionTest, OperatorNotEqual)
+{
+  auto lhs = OpenDriveRoadPosition{"Road1", 1_m, 1_m};
+  auto rhs = OpenDriveRoadPosition{"Road2", 2_m, 2_m};
+
+  ASSERT_NE(lhs, rhs);
+}
+
+TEST(OpenDriveRoadPositionTest, OutputStreamOperator)
+{
+  const auto position = OpenDriveRoadPosition{"Road1", 1_m, 1_m};
+
+  auto oss = std::ostringstream{};
+  oss << position;
+
+  ASSERT_EQ(oss.str(), "OpenDriveRoadPosition(.road=Road1, .s_offset=1 m, .t_offset=1 m)");
+}
+
+/*******************************************************************************
+ * OpenDriveLanePosition
+ *******************************************************************************/
+static_assert(std::is_aggregate_v<OpenDriveLanePosition>);
+
+TEST(OpenDriveLanePositionTest, OperatorEqual)
+{
+  auto lhs = OpenDriveLanePosition{"Road1", -1, 1_m, 1_m};
+  auto rhs = OpenDriveLanePosition{"Road1", -1, 1_m, 1_m};
+
+  ASSERT_EQ(lhs, rhs);
+}
+
+TEST(OpenDriveLanePositionTest, OperatorNotEqual)
+{
+  auto lhs = OpenDriveLanePosition{"Road1", -1, 1_m, 1_m};
+  auto rhs = OpenDriveLanePosition{"Road2", -2, 2_m, 2_m};
+
+  ASSERT_NE(lhs, rhs);
+}
+
+TEST(OpenDriveLanePositionTest, OutputStreamOperator)
+{
+  const auto position = OpenDriveLanePosition{"Road1", -1, 1_m, 1_m};
+
+  auto oss = std::ostringstream{};
+  oss << position;
+
+  ASSERT_EQ(oss.str(), "OpenDriveLanePosition(.road=Road1, .lane=-1, .s_offset=1 m, .t_offset=1 m)");
+}
+
+/*******************************************************************************
+ * LatLonPosition
+ *******************************************************************************/
+static_assert(std::is_trivial_v<LatLonPosition>);
+
+TEST(LatLonPositionTest, OperatorEqual)
+{
+  constexpr const auto lhs = LatLonPosition{1_rad, 1_rad};
+  constexpr const auto rhs = LatLonPosition{1_rad, 1_rad};
+
+  ASSERT_EQ(lhs, rhs);
+
+  static_assert(lhs == rhs);
+}
+
+TEST(LatLonPositionTest, OperatorNotEqual)
+{
+  constexpr const auto lhs = LatLonPosition{1_rad, 1_rad};
+  constexpr const auto rhs = LatLonPosition{2_rad, 2_rad};
+
+  ASSERT_NE(lhs, rhs);
+
+  static_assert(lhs != rhs);
+}
+
+TEST(LatLonPositionTest, OutputStreamOperator)
+{
+  const auto position = LatLonPosition{1_rad, 1_rad};
+
+  auto oss = std::ostringstream{};
+  oss << position;
+
+  ASSERT_EQ(oss.str(), "LatLonPosition(.latitude=1 rad, .longitude=1 rad)");
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Common/spline_test.cc b/test/MantleAPI/Common/spline_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2a32297a14781a5bc3c79e0b8e43590b5cf81ad0
--- /dev/null
+++ b/test/MantleAPI/Common/spline_test.cc
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include "MantleAPI/Common/spline.h"
+
+#include <gtest/gtest.h>
+#include <units.h>
+
+#include <sstream>
+#include <type_traits>
+
+namespace mantle_api
+{
+
+using ::units::literals::operator""_m;
+using ::units::literals::operator""_s;
+
+/*******************************************************************************
+ * SplineSegment
+ *******************************************************************************/
+using SplineSegmentMeterType = SplineSegment<units::length::meter_t>;
+static_assert(std::is_trivial_v<SplineSegmentMeterType>);
+
+TEST(SplineSegmentTest, OperatorEqual)
+{
+  constexpr const auto lhs = SplineSegmentMeterType{
+      {1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}};
+  constexpr const auto rhs = SplineSegmentMeterType{
+      {1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}};
+
+  ASSERT_EQ(lhs, rhs);
+
+  static_assert(lhs == rhs);
+}
+
+TEST(SplineSegmentTest, OperatorNotEqual)
+{
+  constexpr const auto lhs = SplineSegmentMeterType{
+      {1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}};
+  constexpr const auto rhs = SplineSegmentMeterType{
+      {2_m, 2_m, 2_m}, {2_m, 2_m, 2_m}, {2_m, 2_m, 2_m}, {2_m, 2_m, 2_m}};
+
+  ASSERT_NE(lhs, rhs);
+
+  static_assert(lhs != rhs);
+}
+
+TEST(SplineSegmentTest, OutputStreamOperator)
+{
+  const auto spline_segment = SplineSegmentMeterType{
+      {1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}, {1_m, 1_m, 1_m}};
+
+  auto oss = std::ostringstream{};
+  oss << spline_segment;
+
+  ASSERT_EQ(oss.str(), "SplineSegment(.a=Vec3(.x=1 m, .y=1 m, .z=1 m), .b=Vec3(.x=1 m, .y=1 m, .z=1 m), .c=Vec3(.x=1 m, .y=1 m, .z=1 m), .d=Vec3(.x=1 m, .y=1 m, .z=1 m))");
+}
+
+/*******************************************************************************
+ * SplineSection
+ *******************************************************************************/
+using SplineSectionMeterType = SplineSection<units::length::meter>;
+
+static_assert(std::is_trivial_v<SplineSectionMeterType>);
+static_assert(std::is_trivial_v<SplineSectionMeterType::Polynomial>);
+
+TEST(SplineSectionTest, OperatorEqual)
+{
+  constexpr const auto a3_value = 1_m / (3_s * 3_s * 3_s);
+  constexpr const auto a2_value = 1_m / (2_s * 2_s);
+  constexpr const auto a1_value = 1_m / 1_s;
+  constexpr const auto a0_value = 1_m;
+
+  constexpr const auto lhs = SplineSectionMeterType{1_s, 2_s, {a3_value, a2_value, a1_value, a0_value}};
+  constexpr const auto rhs = SplineSectionMeterType{1_s, 2_s, {a3_value, a2_value, a1_value, a0_value}};
+
+  ASSERT_EQ(lhs, rhs);
+
+  static_assert(lhs == rhs);
+}
+
+TEST(SplineSectionTest, OperatorNotEqual)
+{
+  constexpr const auto lhs_a3_value = 1_m / (3_s * 3_s * 3_s);
+  constexpr const auto lhs_a2_value = 1_m / (2_s * 2_s);
+  constexpr const auto lhs_a1_value = 1_m / 1_s;
+  constexpr const auto lhs_a0_value = 1_m;
+
+  constexpr const auto rhs_a3_value = 1_m / (4_s * 4_s * 4_s);
+  constexpr const auto rhs_a2_value = 1_m / (3_s * 3_s);
+  constexpr const auto rhs_a1_value = 1_m / 2_s;
+  constexpr const auto rhs_a0_value = 1_m;
+
+  constexpr const auto lhs = SplineSectionMeterType{1_s, 2_s, {lhs_a3_value, lhs_a2_value, lhs_a1_value, lhs_a0_value}};
+  constexpr const auto rhs = SplineSectionMeterType{2_s, 3_s, {rhs_a3_value, rhs_a2_value, rhs_a1_value, rhs_a0_value}};
+
+  ASSERT_NE(lhs, rhs);
+
+  static_assert(lhs != rhs);
+}
+
+TEST(SplineSectionTest, OutputStreamOperator)
+{
+  const auto spline_section = SplineSectionMeterType{1_s, 2_s, {1_m / (3_s * 3_s * 3_s), 1_m / (2_s * 2_s), 1_m / 1_s, 1_m}};
+
+  auto oss = std::ostringstream{};
+  oss << spline_section;
+
+  ASSERT_EQ(oss.str(), "SplineSection(.start_time=1 s, .end_time=2 s, .polynomial=Polynomial(.a3=0.037037 m s^-3, .a2=0.25 m s^-2, .a1=1 m s^-1, .a0=1 m))");
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Common/trajectory_test.cc b/test/MantleAPI/Common/trajectory_test.cc
index 684315815fc8b59d863971d4f151587a5c77e115..a535bc84ff3dc9b38d0668228559932f7285ff19 100644
--- a/test/MantleAPI/Common/trajectory_test.cc
+++ b/test/MantleAPI/Common/trajectory_test.cc
@@ -1,4 +1,5 @@
 /*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
  * Copyright (c) 2025, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
  *
  * This program and the accompanying materials are made
@@ -8,12 +9,15 @@
  * SPDX-License-Identifier: EPL-2.0
  *******************************************************************************/
 
-#include <MantleAPI/Common/trajectory.h>
+#include "MantleAPI/Common/trajectory.h"
+
 #include <gtest/gtest.h>
+#include <units.h>
 
 #include <functional>
 #include <iostream>
 #include <sstream>
+#include <type_traits>
 #include <variant>
 
 using units::literals::operator""_m;
@@ -25,12 +29,41 @@ using mantle_api::ClothoidSpline;
 using mantle_api::PolyLine;
 using mantle_api::Trajectory;
 
-namespace
+namespace mantle_api
 {
-class TrajectoryTest : public ::testing::Test
+
+static_assert(std::is_aggregate_v<Trajectory>);
+
+TEST(TrajectoryTest, OperatorEqual)
+{
+  const auto lhs = Trajectory{"name", {}, {}};
+  const auto rhs = Trajectory{"name", {}, {}};
+
+  ASSERT_EQ(lhs, rhs);
+}
+
+TEST(TrajectoryTest, OperatorNotEqual)
+{
+  const auto lhs = Trajectory{"name", {}, {}};
+  const auto rhs = Trajectory{"other_name", {}, {}};
+
+  ASSERT_NE(lhs, rhs);
+}
+
+TEST(TrajectoryTest, OutputStreamOperator)
+{
+  const auto trajectory = Trajectory{"name", {}, {}};
+
+  auto oss = std::ostringstream{};
+  oss << trajectory;
+
+  ASSERT_EQ(oss.str(), "Trajectory(.name=name, .type=PolyLine(), reference=0)");
+}
+
+class TrajectoryTestFixture : public ::testing::Test
 {
 public:
-  TrajectoryTest()
+  TrajectoryTestFixture()
   {
     clothoid_spline_.segments.push_back({0.0_curv,
                                          6.6_curv,
@@ -60,7 +93,7 @@ protected:
   Trajectory trajectory_right_;
 };
 
-TEST_F(TrajectoryTest, GivenTrajectories_WhenTrajectoriesHaveEqualParameters_ThenTrajectoryEqualOperatorReturnsTrue)
+TEST_F(TrajectoryTestFixture, GivenTrajectories_WhenTrajectoriesHaveEqualParameters_ThenTrajectoryEqualOperatorReturnsTrue)
 {
   trajectory_left_.type = clothoid_spline_;
   trajectory_right_ = trajectory_left_;
@@ -97,7 +130,7 @@ void ChangeReference(Trajectory& trajectory)
   trajectory.reference = mantle_api::TrajectoryReferencePoint::kRearAxle;
 }
 
-class TrajectoryTestParam : public ::testing::WithParamInterface<ChangeParam>, public TrajectoryTest
+class TrajectoryTestParam : public ::testing::WithParamInterface<ChangeParam>, public TrajectoryTestFixture
 {
 };
 
@@ -121,7 +154,7 @@ TEST_P(TrajectoryTestParam, GivenTrajectories_WhenTrajectoriesHaveDifferentParam
   EXPECT_FALSE(trajectory_left_ == trajectory_right_);
 }
 
-TEST_F(TrajectoryTest, GivenTrajectoryWithNoType_WhenOutputToStream_ThenNoExceptionAndOutputNotEmpty)
+TEST_F(TrajectoryTestFixture, GivenTrajectoryWithNoType_WhenOutputToStream_ThenNoExceptionAndOutputNotEmpty)
 {
   std::stringstream actual_os;
   auto output_to_stream = [](std::ostream& os, Trajectory& trajectory)
@@ -132,7 +165,7 @@ TEST_F(TrajectoryTest, GivenTrajectoryWithNoType_WhenOutputToStream_ThenNoExcept
   EXPECT_GT(actual_os.str().size(), 0);
 }
 
-TEST_F(TrajectoryTest, GivenTrajectoryWithPolylineType_WhenOutputToStream_ThenNoExceptionAndOutputNotEmpty)
+TEST_F(TrajectoryTestFixture, GivenTrajectoryWithPolylineType_WhenOutputToStream_ThenNoExceptionAndOutputNotEmpty)
 {
   std::stringstream actual_os;
   trajectory_left_.type = polyline_;
@@ -144,7 +177,7 @@ TEST_F(TrajectoryTest, GivenTrajectoryWithPolylineType_WhenOutputToStream_ThenNo
   EXPECT_GT(actual_os.str().size(), 0);
 }
 
-TEST_F(TrajectoryTest, GivenTrajectoryWithClothoidSplineType_WhenOutputToStream_ThenNoExceptionAndOutputNotEmpty)
+TEST_F(TrajectoryTestFixture, GivenTrajectoryWithClothoidSplineType_WhenOutputToStream_ThenNoExceptionAndOutputNotEmpty)
 {
   std::stringstream actual_os;
   trajectory_left_.type = clothoid_spline_;
@@ -155,4 +188,5 @@ TEST_F(TrajectoryTest, GivenTrajectoryWithClothoidSplineType_WhenOutputToStream_
   ASSERT_NO_THROW(output_to_stream(actual_os, trajectory_left_));
   EXPECT_GT(actual_os.str().size(), 0);
 }
-}  // namespace
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Common/vector_test.cc b/test/MantleAPI/Common/vector_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2898144524dcfd1a0aa2976f6b63a39335900059
--- /dev/null
+++ b/test/MantleAPI/Common/vector_test.cc
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include "MantleAPI/Common/vector.h"
+
+#include <gtest/gtest.h>
+#include <units.h>
+
+#include <sstream>
+#include <type_traits>
+
+namespace mantle_api
+{
+
+using ::units::literals::operator""_m;
+using Vector3MeterType = Vec3<units::length::meter_t>;
+
+static_assert(std::is_trivial_v<Vector3MeterType>);
+
+TEST(Vec3Test, OperatorEqual)
+{
+  constexpr const auto lhs = Vector3MeterType{1_m, 1_m, 1_m};
+  constexpr const auto rhs = Vector3MeterType{1_m, 1_m, 1_m};
+
+  ASSERT_EQ(lhs, rhs);
+
+  static_assert(lhs == rhs);
+}
+
+TEST(Vec3Test, OperatorNotEqual)
+{
+  constexpr const auto lhs = Vector3MeterType{1_m, 1_m, 1_m};
+  constexpr const auto rhs = Vector3MeterType{2_m, 2_m, 2_m};
+
+  ASSERT_NE(lhs, rhs);
+
+  static_assert(lhs != rhs);
+}
+
+TEST(Vec3Test, Length)
+{
+  constexpr const auto vector = Vector3MeterType{3_m, 4_m, 0_m};
+
+  const auto length = vector.Length();
+
+  ASSERT_EQ(length, 5_m);
+}
+
+TEST(Vec3Test, OperatorMinus)
+{
+  constexpr const auto vector = Vector3MeterType{1_m, 2_m, 3_m};
+  constexpr const auto expected_result = Vector3MeterType{-1_m, -2_m, -3_m};
+
+  constexpr const auto result = -vector;
+
+  ASSERT_EQ(result, expected_result);
+}
+
+TEST(Vec3Test, Add)
+{
+  constexpr const auto lhs = Vector3MeterType{1_m, 2_m, 3_m};
+  constexpr const auto rhs = Vector3MeterType{4_m, 5_m, 6_m};
+  constexpr const auto expected_result = Vector3MeterType{5_m, 7_m, 9_m};
+
+  constexpr const auto result = lhs + rhs;
+
+  ASSERT_EQ(result, expected_result);
+
+  static_assert(result == expected_result);
+}
+
+TEST(Vec3Test, Subtract)
+{
+  constexpr const auto lhs = Vector3MeterType{4_m, 5_m, 6_m};
+  constexpr const auto rhs = Vector3MeterType{1_m, 2_m, 3_m};
+  constexpr const auto expected_result = Vector3MeterType{3_m, 3_m, 3_m};
+
+  constexpr const auto result = lhs - rhs;
+
+  ASSERT_EQ(result, expected_result);
+
+  static_assert(result == expected_result);
+}
+
+TEST(Vec3Test, MultiplyVectorByScalar)
+{
+  constexpr const auto lhs = Vector3MeterType{1_m, 2_m, 3_m};
+  constexpr const auto rhs = 2.0;
+  constexpr const auto expected_result = Vector3MeterType{2_m, 4_m, 6_m};
+
+  constexpr const auto result = lhs * rhs;
+
+  ASSERT_EQ(result, expected_result);
+
+  static_assert(result == expected_result);
+}
+
+TEST(Vec3Test, MultiplyScalarByVector)
+{
+  constexpr const auto lhs = 2.0;
+  constexpr const auto rhs = Vector3MeterType{1_m, 2_m, 3_m};
+  constexpr const auto expected_result = Vector3MeterType{2_m, 4_m, 6_m};
+
+  constexpr const auto vec_mul = lhs * rhs;
+
+  ASSERT_EQ(vec_mul, expected_result);
+
+  static_assert(vec_mul == expected_result);
+}
+
+TEST(Vec3Test, DivideVectorByScalar)
+{
+  constexpr const auto lhs = Vector3MeterType{2_m, 4_m, 6_m};
+  constexpr const auto rhs = 2.0;
+  constexpr const auto expected_result = Vector3MeterType{1_m, 2_m, 3_m};
+
+  constexpr const auto result = lhs / rhs;
+
+  ASSERT_EQ(result, expected_result);
+
+  static_assert(result == expected_result);
+}
+
+TEST(Vec3Test, AddAssign)
+{
+  auto lhs = Vector3MeterType{1_m, 2_m, 3_m};
+  constexpr const auto rhs = Vector3MeterType{4_m, 5_m, 6_m};
+  constexpr const auto expected_result = Vector3MeterType{5_m, 7_m, 9_m};
+
+  lhs += rhs;
+
+  ASSERT_EQ(lhs, expected_result);
+}
+
+TEST(Vec3Test, SubtractAssign)
+{
+  auto lhs = Vector3MeterType{4_m, 5_m, 6_m};
+  constexpr const auto rhs = Vector3MeterType{1_m, 2_m, 3_m};
+  constexpr const auto expected_result = Vector3MeterType{3_m, 3_m, 3_m};
+
+  lhs -= rhs;
+
+  ASSERT_EQ(lhs, expected_result);
+}
+
+TEST(Vec3Test, AddAssignScalar)
+{
+  auto lhs = Vector3MeterType{1_m, 2_m, 3_m};
+  constexpr const auto rhs = 2.0_m;
+  constexpr const auto expected_result = Vector3MeterType{3_m, 4_m, 5_m};
+
+  lhs += rhs;
+
+  ASSERT_EQ(lhs, expected_result);
+}
+
+TEST(Vec3Test, SubtractAssignScalar)
+{
+  auto lhs = Vector3MeterType{4_m, 5_m, 6_m};
+  constexpr const auto rhs = 2.0_m;
+  constexpr const auto expected_result = Vector3MeterType{2_m, 3_m, 4_m};
+
+  lhs -= rhs;
+
+  ASSERT_EQ(lhs, expected_result);
+}
+
+TEST(Vec3Test, OutputStreamOperator)
+{
+  const auto vector = Vector3MeterType{1_m, 2_m, 3_m};
+
+  auto oss = std::ostringstream{};
+  oss << vector;
+
+  ASSERT_EQ(oss.str(), "Vec3(.x=1 m, .y=2 m, .z=3 m)");
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Execution/CMakeLists.txt b/test/MantleAPI/Execution/CMakeLists.txt
index 10fde3f44363c8f0e472d21d4e42ad8a0aa74d83..e64a2e01d3ddcc1946114dde20957b1ead558196 100644
--- a/test/MantleAPI/Execution/CMakeLists.txt
+++ b/test/MantleAPI/Execution/CMakeLists.txt
@@ -9,7 +9,7 @@
 ################################################################################
 
 add_executable(ExecutionTest)
-target_sources(ExecutionTest PUBLIC environment_engine_test.cc)
+target_sources(ExecutionTest PUBLIC environment_engine_test.cc environment_test.cc scenario_engine_test.cc)
 target_include_directories(ExecutionTest PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/test>)
 target_link_libraries(ExecutionTest PUBLIC MantleAPI::MantleAPI GTest::gmock_main)
 
diff --git a/test/MantleAPI/Execution/environment_engine_test.cc b/test/MantleAPI/Execution/environment_engine_test.cc
index 390dd414fa5847ed467a614d4c6c405fabf160d3..c09383f5ddeac6a9afdb84a125600842d92a3760 100644
--- a/test/MantleAPI/Execution/environment_engine_test.cc
+++ b/test/MantleAPI/Execution/environment_engine_test.cc
@@ -11,38 +11,54 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
+#include <utility>
+
 #include "MantleAPI/Execution/i_environment_engine.h"
+#include "MantleAPI/Execution/mock_environment.h"
 #include "MantleAPI/Execution/mock_environment_engine.h"
 
-namespace
+namespace mantle_api
 {
 
 using testing::_;
-using testing::Const;
+using testing::Return;
 
 class EnvironmentEngineTest : public testing::Test
 {
 protected:
-  mantle_api::MockEnvironmentEngine mock_environment_engine_;
-  mantle_api::IEnvironmentEngine &environment_engine_{mock_environment_engine_};
+  MockEnvironmentEngine mock_environment_engine_;
+  IEnvironmentEngine& environment_engine_{mock_environment_engine_};
 };
 
 TEST_F(EnvironmentEngineTest, GetEnvironment)
 {
-  EXPECT_CALL(mock_environment_engine_, GetEnvironment()).Times(1);
-  ASSERT_FALSE(environment_engine_.GetEnvironment());
+  auto mock_environment = MockEnvironment{};
+
+  EXPECT_CALL(mock_environment_engine_, GetEnvironment())
+      .Times(1)
+      .WillOnce(Return(&mock_environment));
+
+  const auto* result = environment_engine_.GetEnvironment();
+
+  ASSERT_TRUE(result);
 }
 
 TEST_F(EnvironmentEngineTest, Step)
 {
-  EXPECT_CALL(mock_environment_engine_, Step(_)).Times(1);
+  EXPECT_CALL(mock_environment_engine_, Step(_))
+      .Times(1);
+
   ASSERT_NO_THROW(environment_engine_.Step({}));
 }
 
 TEST_F(EnvironmentEngineTest, GetDesiredDeltaTime)
 {
-  EXPECT_CALL(Const(mock_environment_engine_), GetDesiredDeltaTime()).Times(1);
-  ASSERT_FALSE(environment_engine_.GetDesiredDeltaTime());
+  EXPECT_CALL(std::as_const(mock_environment_engine_), GetDesiredDeltaTime())
+      .Times(1);
+
+  auto result = std::as_const(environment_engine_).GetDesiredDeltaTime();
+
+  ASSERT_FALSE(result);
 }
 
-}  // namespace
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Execution/environment_test.cc b/test/MantleAPI/Execution/environment_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0bb0bb0b1d101dc66e849a8ec8a91f4dea3eb194
--- /dev/null
+++ b/test/MantleAPI/Execution/environment_test.cc
@@ -0,0 +1,305 @@
+/*******************************************************************************
+ * Copyright (c) 2023, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utility>
+
+#include "MantleAPI/Common/mock_geometry_helper.h"
+#include "MantleAPI/Execution/mock_environment.h"
+#include "MantleAPI/Map/mock_coord_converter.h"
+#include "MantleAPI/Map/mock_lane_location_query_service.h"
+#include "MantleAPI/Map/mock_route_repository.h"
+#include "MantleAPI/Traffic/mock_controller_repository.h"
+#include "MantleAPI/Traffic/mock_entity.h"
+#include "MantleAPI/Traffic/mock_entity_repository.h"
+#include "MantleAPI/Traffic/mock_traffic_area_service.h"
+#include "MantleAPI/Traffic/mock_traffic_swarm_service.h"
+
+namespace mantle_api
+{
+
+using testing::_;
+using testing::Return;
+using testing::ReturnRef;
+
+class EnvironmentTest : public testing::Test
+{
+protected:
+  MockEnvironment mock_environment_;
+  IEnvironment& environment_{mock_environment_};
+};
+
+TEST_F(EnvironmentTest, CreateMap)
+{
+  EXPECT_CALL(mock_environment_, CreateMap(_, _, _))
+      .Times(1);
+
+  environment_.CreateMap({}, {}, {});
+}
+
+TEST_F(EnvironmentTest, AddEntityToController)
+{
+  EXPECT_CALL(mock_environment_, AddEntityToController(_, _))
+      .Times(1);
+
+  auto entity = MockEntity{};
+
+  environment_.AddEntityToController(entity, {});
+}
+
+TEST_F(EnvironmentTest, RemoveEntityFromController)
+{
+  EXPECT_CALL(mock_environment_, RemoveEntityFromController(_, _))
+      .Times(1);
+
+  environment_.RemoveEntityFromController({}, {});
+}
+
+TEST_F(EnvironmentTest, UpdateControlStrategies)
+{
+  EXPECT_CALL(mock_environment_, UpdateControlStrategies(_, _))
+      .Times(1);
+
+  environment_.UpdateControlStrategies({}, {});
+}
+
+TEST_F(EnvironmentTest, HasControlStrategyGoalBeenReached)
+{
+  EXPECT_CALL(std::as_const(mock_environment_), HasControlStrategyGoalBeenReached(_, _))
+      .Times(1)
+      .WillOnce(Return(true));
+
+  std::ignore = std::as_const(environment_).HasControlStrategyGoalBeenReached({}, {});
+}
+
+TEST_F(EnvironmentTest, GetQueryService)
+{
+  const auto mock_lane_location_query_service = MockLaneLocationQueryService{};
+
+  EXPECT_CALL(std::as_const(mock_environment_), GetQueryService())
+      .Times(1)
+      .WillOnce(ReturnRef(mock_lane_location_query_service));
+
+  std::ignore = std::as_const(environment_).GetQueryService();
+}
+
+TEST_F(EnvironmentTest, GetConverter)
+{
+  auto mock_coord_converter = MockCoordConverter{};
+
+  EXPECT_CALL(mock_environment_, GetConverter())
+      .Times(1)
+      .WillOnce(Return(&mock_coord_converter));
+
+  std::ignore = environment_.GetConverter();
+}
+
+TEST_F(EnvironmentTest, GetGeometryHelper)
+{
+  auto mock_geometry_helper = MockGeometryHelper{};
+
+  EXPECT_CALL(std::as_const(mock_environment_), GetGeometryHelper())
+      .Times(1)
+      .WillOnce(Return(&mock_geometry_helper));
+
+  std::ignore = std::as_const(environment_).GetGeometryHelper();
+}
+
+TEST_F(EnvironmentTest, GetEntityRepository)
+{
+  auto mock_entity_repository = MockEntityRepository{};
+
+  EXPECT_CALL(mock_environment_, GetEntityRepository())
+      .Times(1)
+      .WillOnce(ReturnRef(mock_entity_repository));
+
+  std::ignore = environment_.GetEntityRepository();
+}
+
+TEST_F(EnvironmentTest, GetEntityRepositoryConst)
+{
+  const auto mock_entity_repository = MockEntityRepository{};
+
+  EXPECT_CALL(std::as_const(mock_environment_), GetEntityRepository())
+      .Times(1)
+      .WillOnce(ReturnRef(mock_entity_repository));
+
+  std::ignore = std::as_const(environment_).GetEntityRepository();
+}
+
+TEST_F(EnvironmentTest, GetControllerRepository)
+{
+  auto mock_controller_repository = MockControllerRepository{};
+
+  EXPECT_CALL(mock_environment_, GetControllerRepository())
+      .Times(1)
+      .WillOnce(ReturnRef(mock_controller_repository));
+
+  std::ignore = environment_.GetControllerRepository();
+}
+
+TEST_F(EnvironmentTest, GetControllerRepositoryConst)
+{
+  const auto mock_controller_repository = MockControllerRepository{};
+
+  EXPECT_CALL(std::as_const(mock_environment_), GetControllerRepository())
+      .Times(1)
+      .WillOnce(ReturnRef(mock_controller_repository));
+
+  std::ignore = std::as_const(environment_).GetControllerRepository();
+}
+
+TEST_F(EnvironmentTest, GetRouteRepository)
+{
+  auto mock_route_repository = MockRouteRepository{};
+
+  EXPECT_CALL(mock_environment_, GetRouteRepository())
+      .Times(1)
+      .WillOnce(ReturnRef(mock_route_repository));
+
+  std::ignore = environment_.GetRouteRepository();
+}
+
+TEST_F(EnvironmentTest, GetRouteRepositoryConst)
+{
+  const auto mock_route_repository = MockRouteRepository{};
+
+  EXPECT_CALL(std::as_const(mock_environment_), GetRouteRepository())
+      .Times(1)
+      .WillOnce(ReturnRef(mock_route_repository));
+
+  std::ignore = std::as_const(environment_).GetRouteRepository();
+}
+
+TEST_F(EnvironmentTest, SetDateTime)
+{
+  EXPECT_CALL(mock_environment_, SetDateTime(_))
+      .Times(1);
+  environment_.SetDateTime({});
+}
+
+TEST_F(EnvironmentTest, GetDateTime)
+{
+  EXPECT_CALL(mock_environment_, GetDateTime())
+      .Times(1)
+      .WillOnce(Return(Time{}));
+
+  std::ignore = environment_.GetDateTime();
+}
+
+TEST_F(EnvironmentTest, GetSimulationTime)
+{
+  EXPECT_CALL(mock_environment_, GetSimulationTime())
+      .Times(1)
+      .WillOnce(Return(Time{}));
+
+  std::ignore = environment_.GetSimulationTime();
+}
+
+TEST_F(EnvironmentTest, SetWeather)
+{
+  EXPECT_CALL(mock_environment_, SetWeather(_))
+      .Times(1);
+  environment_.SetWeather({});
+}
+
+TEST_F(EnvironmentTest, SetRoadCondition)
+{
+  EXPECT_CALL(mock_environment_, SetRoadCondition(_))
+      .Times(1);
+  environment_.SetRoadCondition({});
+}
+
+TEST_F(EnvironmentTest, SetTrafficSignalState)
+{
+  EXPECT_CALL(mock_environment_, SetTrafficSignalState(_, _))
+      .Times(1);
+  environment_.SetTrafficSignalState({}, {});
+}
+
+TEST_F(EnvironmentTest, ExecuteCustomCommand)
+{
+  EXPECT_CALL(mock_environment_, ExecuteCustomCommand(_, _, _))
+      .Times(1);
+  environment_.ExecuteCustomCommand({}, {}, {});
+}
+
+TEST_F(EnvironmentTest, SetUserDefinedValue)
+{
+  EXPECT_CALL(mock_environment_, SetUserDefinedValue(_, _))
+      .Times(1);
+  environment_.SetUserDefinedValue({}, {});
+}
+
+TEST_F(EnvironmentTest, GetUserDefinedValue)
+{
+  EXPECT_CALL(std::as_const(mock_environment_), GetUserDefinedValue(_))
+      .Times(1)
+      .WillOnce(Return(std::nullopt));
+  std::ignore = std::as_const(environment_).GetUserDefinedValue({});
+}
+
+TEST_F(EnvironmentTest, SetVariable)
+{
+  EXPECT_CALL(mock_environment_, SetVariable(_, _))
+      .Times(1);
+
+  environment_.SetVariable({}, {});
+}
+
+TEST_F(EnvironmentTest, GetVariable)
+{
+  EXPECT_CALL(std::as_const(mock_environment_), GetVariable(_))
+      .Times(1)
+      .WillOnce(Return(std::nullopt));
+  std::ignore = std::as_const(environment_).GetVariable({});
+}
+
+TEST_F(EnvironmentTest, SetDefaultRoutingBehavior)
+{
+  EXPECT_CALL(mock_environment_, SetDefaultRoutingBehavior(_))
+      .Times(1);
+
+  environment_.SetDefaultRoutingBehavior({});
+}
+
+TEST_F(EnvironmentTest, InitTrafficSwarmService)
+{
+  EXPECT_CALL(mock_environment_, InitTrafficSwarmService(_))
+      .Times(1);
+
+  environment_.InitTrafficSwarmService({});
+}
+
+TEST_F(EnvironmentTest, GetTrafficSwarmService)
+{
+  auto mock_traffic_swarm_service = MockTrafficSwarmService{};
+
+  EXPECT_CALL(mock_environment_, GetTrafficSwarmService())
+      .Times(1)
+      .WillOnce(ReturnRef(mock_traffic_swarm_service));
+
+  std::ignore = environment_.GetTrafficSwarmService();
+}
+
+TEST_F(EnvironmentTest, GetTrafficAreaService)
+{
+  auto mock_traffic_area_service = MockTrafficAreaService{};
+
+  EXPECT_CALL(mock_environment_, GetTrafficAreaService())
+      .Times(1)
+      .WillOnce(ReturnRef(mock_traffic_area_service));
+
+  std::ignore = environment_.GetTrafficAreaService();
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Execution/mock_environment.h b/test/MantleAPI/Execution/mock_environment.h
new file mode 100644
index 0000000000000000000000000000000000000000..10d7c4877e618d8e7039fa76d66dc9025ec816c3
--- /dev/null
+++ b/test/MantleAPI/Execution/mock_environment.h
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2023, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#ifndef MANTLEAPI_EXECUTION_MOCK_ENVIRONMENT_H
+#define MANTLEAPI_EXECUTION_MOCK_ENVIRONMENT_H
+
+#include <gmock/gmock.h>
+
+#include <memory>
+#include <optional>
+#include <string>
+#include <vector>
+
+#include "MantleAPI/Common/i_identifiable.h"  // for UniqueId
+#include "MantleAPI/Common/time_utils.h"
+#include "MantleAPI/EnvironmentalConditions/road_condition.h"
+#include "MantleAPI/EnvironmentalConditions/weather.h"
+#include "MantleAPI/Execution/i_environment.h"
+#include "MantleAPI/Map/i_route_repository.h"
+#include "MantleAPI/Map/map_details.h"
+#include "MantleAPI/Traffic/control_strategy.h"
+#include "MantleAPI/Traffic/default_routing_behavior.h"
+#include "MantleAPI/Traffic/i_controller_repository.h"
+#include "MantleAPI/Traffic/i_entity.h"
+
+namespace mantle_api
+{
+
+class ILaneLocationQueryService;
+class ICoordConverter;
+class IGeometryHelper;
+class IEntityRepository;
+class IControllerRepository;
+
+class MockEnvironment : public IEnvironment
+{
+public:
+  MOCK_METHOD(void, CreateMap, (const std::string& map_file_path, const MapDetails& map_details, const std::string& map_model_reference), (override));
+  MOCK_METHOD(void, AddEntityToController, (IEntity & entity, UniqueId controller_id), (override));
+  MOCK_METHOD(void, RemoveEntityFromController, (UniqueId entity_id, UniqueId controller_id), (override));
+  MOCK_METHOD(void, UpdateControlStrategies, (UniqueId entity_id, std::vector<std::shared_ptr<ControlStrategy>> control_strategies), (override));
+  MOCK_METHOD(bool, HasControlStrategyGoalBeenReached, (UniqueId entity_id, ControlStrategyType type), (const, override));
+  MOCK_METHOD(const ILaneLocationQueryService&, GetQueryService, (), (const, override));
+  MOCK_METHOD(ICoordConverter*, GetConverter, (), (override));
+  MOCK_METHOD(const IGeometryHelper*, GetGeometryHelper, (), (const, override));
+  MOCK_METHOD(IEntityRepository&, GetEntityRepository, (), (override));
+  MOCK_METHOD(const IEntityRepository&, GetEntityRepository, (), (const, override));
+  MOCK_METHOD(IControllerRepository&, GetControllerRepository, (), (override));
+  MOCK_METHOD(const IControllerRepository&, GetControllerRepository, (), (const, override));
+  MOCK_METHOD(IRouteRepository&, GetRouteRepository, (), (override));
+  MOCK_METHOD(const IRouteRepository&, GetRouteRepository, (), (const, override));
+  MOCK_METHOD(void, SetDateTime, (Time time), (override));
+  MOCK_METHOD(Time, GetDateTime, (), (override));
+  MOCK_METHOD(Time, GetSimulationTime, (), (override));
+  MOCK_METHOD(void, SetWeather, (Weather weather), (override));
+  MOCK_METHOD(void, SetRoadCondition, (std::vector<FrictionPatch> friction_patches), (override));
+  MOCK_METHOD(void, SetTrafficSignalState, (const std::string& traffic_signal_name, const std::string& traffic_signal_state), (override));
+  MOCK_METHOD(void, ExecuteCustomCommand, (const std::vector<std::string>& actors, const std::string& type, const std::string& command), (override));
+  MOCK_METHOD(void, SetUserDefinedValue, (const std::string& name, const std::string& value), (override));
+  MOCK_METHOD(std::optional<std::string>, GetUserDefinedValue, (const std::string& name), (const, override));
+  MOCK_METHOD(void, SetVariable, (const std::string& name, const ParameterType& value), (override));
+  MOCK_METHOD(std::optional<ParameterType>, GetVariable, (const std::string& name), (const, override));
+  MOCK_METHOD(void, SetDefaultRoutingBehavior, (DefaultRoutingBehavior default_routing_behavior), (override));
+  MOCK_METHOD(void, InitTrafficSwarmService, (const TrafficSwarmParameters& parameters), (override));
+  MOCK_METHOD(ITrafficSwarmService&, GetTrafficSwarmService, (), (override));
+  MOCK_METHOD(ITrafficAreaService&, GetTrafficAreaService, (), (override));
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_EXECUTION_MOCK_ENVIRONMENT_H
diff --git a/test/MantleAPI/Execution/mock_environment_engine.h b/test/MantleAPI/Execution/mock_environment_engine.h
index d8007f47dd93c47b46030799e384dd5ca3ebee2e..18393358bae0c37fa492dd6a402f1bbf8915de86 100644
--- a/test/MantleAPI/Execution/mock_environment_engine.h
+++ b/test/MantleAPI/Execution/mock_environment_engine.h
@@ -8,17 +8,21 @@
  * SPDX-License-Identifier: EPL-2.0
  *******************************************************************************/
 
-#ifndef MANTLEAPI_COMMON_MOCK_ENVIRONMENT_ENGINE_H
-#define MANTLEAPI_COMMON_MOCK_ENVIRONMENT_ENGINE_H
+#ifndef MANTLEAPI_EXECUTION_MOCK_ENVIRONMENT_ENGINE_H
+#define MANTLEAPI_EXECUTION_MOCK_ENVIRONMENT_ENGINE_H
 
 #include <gmock/gmock.h>
 
+#include <optional>
+
 #include "MantleAPI/Execution/i_environment_engine.h"
 
 namespace mantle_api
 {
 
-class MockEnvironmentEngine final : public IEnvironmentEngine
+class IEnvironment;
+
+class MockEnvironmentEngine : public IEnvironmentEngine
 {
 public:
   MOCK_METHOD(IEnvironment*, GetEnvironment, (), (noexcept, override));
@@ -28,4 +32,4 @@ public:
 
 }  // namespace mantle_api
 
-#endif  // MANTLEAPI_COMMON_MOCK_ENVIRONMENT_ENGINE_H
+#endif  // MANTLEAPI_EXECUTION_MOCK_ENVIRONMENT_ENGINE_H
diff --git a/test/MantleAPI/Execution/mock_scenario_engine.h b/test/MantleAPI/Execution/mock_scenario_engine.h
new file mode 100644
index 0000000000000000000000000000000000000000..400d98e8b35271f457c0723f3768c1f19197c840
--- /dev/null
+++ b/test/MantleAPI/Execution/mock_scenario_engine.h
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#ifndef MANTLEAPI_EXECUTION_MOCK_SCENARIO_ENGINE_H
+#define MANTLEAPI_EXECUTION_MOCK_SCENARIO_ENGINE_H
+
+#include <gmock/gmock.h>
+
+#include <optional>
+
+#include "MantleAPI/Common/time_utils.h"
+#include "MantleAPI/Execution/i_scenario_engine.h"
+#include "MantleAPI/Execution/scenario_info.h"
+
+namespace mantle_api
+{
+
+class IEnvironment;
+
+class MockScenarioEngine : public IScenarioEngine
+{
+public:
+  MOCK_METHOD(void, Init, (), (override));
+  MOCK_METHOD(ScenarioInfo, GetScenarioInfo, (), (const, override));
+  MOCK_METHOD(void, SetupDynamicContent, (), (override));
+  MOCK_METHOD(bool, IsFinished, (), (const, override));
+  MOCK_METHOD(void, ActivateExternalHostControl, (), (override));
+  MOCK_METHOD(int, ValidateScenario, (), (override));
+
+  MOCK_METHOD(void, Step, (Time), (override));
+  MOCK_METHOD(std::optional<Time>, GetDesiredDeltaTime, (), (const, noexcept, override));
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_EXECUTION_MOCK_SCENARIO_ENGINE_H
diff --git a/test/MantleAPI/Execution/scenario_engine_test.cc b/test/MantleAPI/Execution/scenario_engine_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..2ee773fae5b8a33662ea2c93013d323bd12baac2
--- /dev/null
+++ b/test/MantleAPI/Execution/scenario_engine_test.cc
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utility>
+
+#include "MantleAPI/Execution/i_scenario_engine.h"
+#include "MantleAPI/Execution/mock_scenario_engine.h"
+
+namespace mantle_api
+{
+
+using testing::_;
+using testing::Return;
+
+class ScenarioEngineTest : public testing::Test
+{
+protected:
+  MockScenarioEngine mock_scenario_engine_;
+  IScenarioEngine& scenario_engine_{mock_scenario_engine_};
+};
+
+TEST_F(ScenarioEngineTest, Init)
+{
+  EXPECT_CALL(mock_scenario_engine_, Init())
+      .Times(1);
+
+  scenario_engine_.Init();
+}
+
+TEST_F(ScenarioEngineTest, GetScenarioInfo)
+{
+  auto mock_scenario_info = ScenarioInfo{};
+
+  EXPECT_CALL(std::as_const(mock_scenario_engine_), GetScenarioInfo())
+      .Times(1)
+      .WillOnce(Return(mock_scenario_info));
+
+  std::ignore = std::as_const(scenario_engine_).GetScenarioInfo();
+}
+
+TEST_F(ScenarioEngineTest, SetupDynamicContent)
+{
+  EXPECT_CALL(mock_scenario_engine_, SetupDynamicContent())
+      .Times(1);
+
+  scenario_engine_.SetupDynamicContent();
+}
+
+TEST_F(ScenarioEngineTest, IsFinished)
+{
+  EXPECT_CALL(std::as_const(mock_scenario_engine_), IsFinished())
+      .Times(1);
+
+  auto result = std::as_const(scenario_engine_).IsFinished();
+
+  ASSERT_FALSE(result);
+}
+
+TEST_F(ScenarioEngineTest, ActivateExternalHostControl)
+{
+  EXPECT_CALL(mock_scenario_engine_, ActivateExternalHostControl())
+      .Times(1);
+
+  scenario_engine_.ActivateExternalHostControl();
+}
+
+TEST_F(ScenarioEngineTest, ValidateScenario)
+{
+  EXPECT_CALL(mock_scenario_engine_, ValidateScenario())
+      .Times(1);
+
+  auto result = scenario_engine_.ValidateScenario();
+
+  ASSERT_EQ(result, 0);
+}
+
+TEST_F(ScenarioEngineTest, Step)
+{
+  EXPECT_CALL(mock_scenario_engine_, Step(_))
+      .Times(1);
+
+  scenario_engine_.Step({});
+}
+
+TEST_F(ScenarioEngineTest, GetDesiredDeltaTime)
+{
+  EXPECT_CALL(std::as_const(mock_scenario_engine_), GetDesiredDeltaTime())
+      .Times(1);
+
+  auto result = std::as_const(scenario_engine_).GetDesiredDeltaTime();
+
+  ASSERT_FALSE(result);
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Map/CMakeLists.txt b/test/MantleAPI/Map/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..19828fa4c125a82518286418f7c1fe8814349081
--- /dev/null
+++ b/test/MantleAPI/Map/CMakeLists.txt
@@ -0,0 +1,19 @@
+################################################################################
+# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH
+#
+# This program and the accompanying materials are made available under the terms
+# of the Eclipse Public License 2.0 which is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+################################################################################
+
+add_executable(MapTest)
+target_sources(
+  MapTest PUBLIC coord_converter_test.cc lane_location_query_service_test.cc route_test.cc routing_definition_test.cc
+)
+target_include_directories(MapTest PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/test>)
+target_link_libraries(MapTest PUBLIC MantleAPI::MantleAPI GTest::gmock_main)
+
+include(GoogleTest)
+gtest_discover_tests(MapTest)
diff --git a/test/MantleAPI/Map/coord_converter_test.cc b/test/MantleAPI/Map/coord_converter_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e40a93b7ec72e128652062df75c20a041afd26f3
--- /dev/null
+++ b/test/MantleAPI/Map/coord_converter_test.cc
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <units.h>
+
+#include <tuple>
+
+#include "MantleAPI/Map/i_coord_converter.h"
+#include "MantleAPI/Map/mock_coord_converter.h"
+
+namespace mantle_api
+{
+
+using testing::_;
+using testing::Return;
+
+class CoordConverterTest : public testing::Test
+{
+protected:
+  MockCoordConverter mock_coord_converter_;
+  ICoordConverter& coord_converter_{mock_coord_converter_};
+};
+
+TEST_F(CoordConverterTest, Convert)
+{
+  static const auto kPosition = Position{};
+  static const auto kReturnValue = Vec3<units::length::meter_t>{};
+
+  EXPECT_CALL(mock_coord_converter_, Convert(_))
+      .Times(1)
+      .WillOnce(Return(kReturnValue));
+
+  std::ignore = coord_converter_.Convert(kPosition);
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Map/lane_location_query_service_test.cc b/test/MantleAPI/Map/lane_location_query_service_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..27ab4b8342ba26f0b8919f7de6aab86700b7364a
--- /dev/null
+++ b/test/MantleAPI/Map/lane_location_query_service_test.cc
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <units.h>
+
+#include <optional>
+#include <tuple>
+#include <vector>
+
+#include "MantleAPI/Map/mock_lane_location_query_service.h"
+
+namespace mantle_api
+{
+
+using testing::_;
+using testing::Return;
+
+class LaneLocationQueryServiceTest : public testing::Test
+{
+protected:
+  MockLaneLocationQueryService mock_lane_location_query_service_;
+  ILaneLocationQueryService& lane_location_query_service_{mock_lane_location_query_service_};
+};
+
+TEST_F(LaneLocationQueryServiceTest, GetLaneOrientation)
+{
+  EXPECT_CALL(std::as_const(mock_lane_location_query_service_), GetLaneOrientation(_))
+      .Times(1)
+      .WillOnce(Return(Orientation3<units::angle::radian_t>{}));
+
+  std::ignore = std::as_const(lane_location_query_service_).GetLaneOrientation({});
+}
+
+TEST_F(LaneLocationQueryServiceTest, GetUpwardsShiftedLanePosition)
+{
+  EXPECT_CALL(std::as_const(mock_lane_location_query_service_), GetUpwardsShiftedLanePosition(_, _, _))
+      .Times(1)
+      .WillOnce(Return(Vec3<units::length::meter_t>{}));
+
+  std::ignore = std::as_const(lane_location_query_service_).GetUpwardsShiftedLanePosition({}, {}, {});
+}
+
+TEST_F(LaneLocationQueryServiceTest, IsPositionOnLane)
+{
+  EXPECT_CALL(std::as_const(mock_lane_location_query_service_), IsPositionOnLane(_))
+      .Times(1)
+      .WillOnce(Return(true));
+
+  std::ignore = std::as_const(lane_location_query_service_).IsPositionOnLane({});
+}
+
+TEST_F(LaneLocationQueryServiceTest, GetLaneIdsAtPosition)
+{
+  EXPECT_CALL(std::as_const(mock_lane_location_query_service_), GetLaneIdsAtPosition(_))
+      .Times(1)
+      .WillOnce(Return(std::vector<UniqueId>{}));
+
+  std::ignore = std::as_const(lane_location_query_service_).GetLaneIdsAtPosition({});
+}
+
+TEST_F(LaneLocationQueryServiceTest, FindLanePoseAtDistanceFrom)
+{
+  EXPECT_CALL(std::as_const(mock_lane_location_query_service_), FindLanePoseAtDistanceFrom(_, _, _))
+      .Times(1)
+      .WillOnce(Return(std::make_optional<Pose>()));
+
+  std::ignore = std::as_const(lane_location_query_service_).FindLanePoseAtDistanceFrom({}, {}, {});
+}
+
+TEST_F(LaneLocationQueryServiceTest, GetLongitudinalLaneDistanceBetweenPositions)
+{
+  EXPECT_CALL(std::as_const(mock_lane_location_query_service_), GetLongitudinalLaneDistanceBetweenPositions(_, _))
+      .Times(1)
+      .WillOnce(Return(std::make_optional<units::length::meter_t>()));
+
+  std::ignore = std::as_const(lane_location_query_service_).GetLongitudinalLaneDistanceBetweenPositions({}, {});
+}
+
+TEST_F(LaneLocationQueryServiceTest, FindRelativeLanePoseAtDistanceFrom)
+{
+  EXPECT_CALL(std::as_const(mock_lane_location_query_service_), FindRelativeLanePoseAtDistanceFrom(_, _, _, _))
+      .Times(1)
+      .WillOnce(Return(std::make_optional<Pose>()));
+
+  std::ignore = std::as_const(lane_location_query_service_).FindRelativeLanePoseAtDistanceFrom({}, {}, {}, {});
+}
+
+TEST_F(LaneLocationQueryServiceTest, GetRelativeLaneId)
+{
+  EXPECT_CALL(std::as_const(mock_lane_location_query_service_), GetRelativeLaneId(_, _))
+      .Times(1)
+      .WillOnce(Return(std::make_optional<LaneId>()));
+
+  std::ignore = std::as_const(lane_location_query_service_).GetRelativeLaneId({}, {});
+}
+
+TEST_F(LaneLocationQueryServiceTest, GetProjectedPoseAtLane)
+{
+  EXPECT_CALL(std::as_const(mock_lane_location_query_service_), GetProjectedPoseAtLane(_, _))
+      .Times(1)
+      .WillOnce(Return(std::make_optional<Pose>()));
+
+  std::ignore = std::as_const(lane_location_query_service_).GetProjectedPoseAtLane({}, {});
+}
+
+TEST_F(LaneLocationQueryServiceTest, GetProjectedCenterLinePoint)
+{
+  EXPECT_CALL(std::as_const(mock_lane_location_query_service_), GetProjectedCenterLinePoint(_))
+      .Times(1)
+      .WillOnce(Return(std::make_optional<Vec3<units::length::meter_t>>()));
+
+  std::ignore = std::as_const(lane_location_query_service_).GetProjectedCenterLinePoint({});
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Map/mock_coord_converter.h b/test/MantleAPI/Map/mock_coord_converter.h
new file mode 100644
index 0000000000000000000000000000000000000000..5323ebef808483872b3b6d59880ad2f7e379af5b
--- /dev/null
+++ b/test/MantleAPI/Map/mock_coord_converter.h
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#ifndef MANTLEAPI_MAP_MOCK_COORD_CONVERTER_H
+#define MANTLEAPI_MAP_MOCK_COORD_CONVERTER_H
+
+#include <gmock/gmock.h>
+#include <units.h>
+
+#include "MantleAPI/Common/position.h"
+#include "MantleAPI/Map/i_coord_converter.h"
+
+namespace mantle_api
+{
+
+class MockCoordConverter : public ICoordConverter
+{
+public:
+  MOCK_METHOD(Vec3<units::length::meter_t>, Convert, (Position position), (override));
+  MOCK_METHOD(Orientation3<units::angle::radian_t>, GetLaneOrientation, (const OpenDriveLanePosition& open_drive_lane_position), ());
+  MOCK_METHOD(Orientation3<units::angle::radian_t>, GetRoadOrientation, (const OpenDriveRoadPosition& open_drive_road_position), ());
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_MAP_MOCK_COORD_CONVERTER_H
diff --git a/test/MantleAPI/Map/mock_lane_location_query_service.h b/test/MantleAPI/Map/mock_lane_location_query_service.h
new file mode 100644
index 0000000000000000000000000000000000000000..25ddefd686e4b773c3b43da6cf497a550dcd0aee
--- /dev/null
+++ b/test/MantleAPI/Map/mock_lane_location_query_service.h
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#ifndef MANTLEAPI_MAP_MOCK_LANE_LOCATION_QUERY_SERVICE_H
+#define MANTLEAPI_MAP_MOCK_LANE_LOCATION_QUERY_SERVICE_H
+
+#include <gmock/gmock.h>
+#include <units.h>
+
+#include <optional>
+#include <vector>
+
+#include "MantleAPI/Common/i_identifiable.h"
+#include "MantleAPI/Common/orientation.h"
+#include "MantleAPI/Common/pose.h"
+#include "MantleAPI/Common/vector.h"
+#include "MantleAPI/Map/i_lane_location_query_service.h"
+#include "MantleAPI/Map/lane_definition.h"
+
+namespace mantle_api
+{
+
+class MockLaneLocationQueryService : public ILaneLocationQueryService
+{
+public:
+  MOCK_METHOD(Orientation3<units::angle::radian_t>,  //
+              GetLaneOrientation,
+              (const Vec3<units::length::meter_t>& position),
+              (const, override));
+  MOCK_METHOD(Vec3<units::length::meter_t>,  //
+              GetUpwardsShiftedLanePosition,
+              (const Vec3<units::length::meter_t>& position, double upwards_shift, bool allow_invalid_positions),
+              (const, override));
+  MOCK_METHOD(bool, IsPositionOnLane,  //
+              (const Vec3<units::length::meter_t>& position),
+              (const, override));
+  MOCK_METHOD(std::vector<UniqueId>,  //
+              GetLaneIdsAtPosition,
+              (const Vec3<units::length::meter_t>& position),
+              (const, override));
+  MOCK_METHOD(std::optional<Pose>,  //
+              FindLanePoseAtDistanceFrom,
+              (const Pose& reference_pose_on_lane, units::length::meter_t distance, Direction direction),
+              (const, override));
+  MOCK_METHOD(std::optional<Vec3<units::length::meter_t>>,  //
+              GetPosition,
+              (const mantle_api::Pose& reference_pose, mantle_api::LateralDisplacementDirection direction, units::length::meter_t distance),
+              (const, override));
+  MOCK_METHOD(std::optional<units::length::meter_t>,  //
+              GetLongitudinalLaneDistanceBetweenPositions,
+              (const mantle_api::Vec3<units::length::meter_t>& start_position, const mantle_api::Vec3<units::length::meter_t>& target_position),
+              (const, override));
+  MOCK_METHOD(std::optional<Pose>,  //
+              FindRelativeLanePoseAtDistanceFrom,
+              (const Pose& reference_pose_on_lane, int relative_target_lane, units::length::meter_t distance, units::length::meter_t lateral_offset),
+              (const, override));
+  MOCK_METHOD(std::optional<mantle_api::LaneId>,  //
+              GetRelativeLaneId,
+              (const mantle_api::Pose& reference_pose_on_lane, int relative_lane_target),
+              (const, override));
+  MOCK_METHOD(std::optional<mantle_api::Pose>,  //
+              GetProjectedPoseAtLane,
+              (const Vec3<units::length::meter_t>& reference_position_on_lane,
+               mantle_api::UniqueId target_lane_id),
+              (const, override));
+  MOCK_METHOD(std::optional<Vec3<units::length::meter_t>>,  //
+              GetProjectedCenterLinePoint,
+              (const Vec3<units::length::meter_t>& position),
+              (const, override));
+  MOCK_METHOD(units::length::meter_t,  //
+              GetLaneHeightAtPosition,
+              (const Vec3<units::length::meter_t>& position),
+              (const, override));
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_MAP_MOCK_LANE_LOCATION_QUERY_SERVICE_H
diff --git a/test/MantleAPI/Map/mock_route.h b/test/MantleAPI/Map/mock_route.h
new file mode 100644
index 0000000000000000000000000000000000000000..0761bd894c2cffb02e661f86baca4c559b1734a4
--- /dev/null
+++ b/test/MantleAPI/Map/mock_route.h
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#ifndef MANTLEAPI_MAP_MOCK_ROUTE_H
+#define MANTLEAPI_MAP_MOCK_ROUTE_H
+
+#include <gmock/gmock.h>
+
+#include <memory>
+
+#include "MantleAPI/Common/position.h"
+#include "MantleAPI/Map/i_route.h"
+
+namespace mantle_api
+{
+
+class MockRoute : public IRoute
+{
+public:
+  // IIdentifiable
+  MOCK_METHOD(UniqueId, GetUniqueId, (), (const, override));
+
+  MOCK_METHOD(void, SetName, (const std::string& name), (override));
+
+  MOCK_METHOD(const std::string&, GetName, (), (const, override));
+
+  // IRoute
+  MOCK_METHOD(bool, IsLooped, (), (const, override));
+  MOCK_METHOD(std::optional<units::length::meter_t>, GetOffsetAlongReferenceLine, (const Position& position), (const, override));
+  MOCK_METHOD(OpenDriveRoadPosition, ProjectAlongReferenceLine, (units::length::meter_t longitudinal_offset, units::length::meter_t lateral_offset), (const, override));
+  MOCK_METHOD(units::length::meter_t, GetLength, (), (const, override));
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_MAP_MOCK_ROUTE_H
diff --git a/test/MantleAPI/Map/mock_route_repository.h b/test/MantleAPI/Map/mock_route_repository.h
new file mode 100644
index 0000000000000000000000000000000000000000..159b3a8ef9179ee4186c72af35e987da3e8bad00
--- /dev/null
+++ b/test/MantleAPI/Map/mock_route_repository.h
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#ifndef MANTLEAPI_MAP_MOCK_ROUTE_REPOSITORY_H
+#define MANTLEAPI_MAP_MOCK_ROUTE_REPOSITORY_H
+
+#include <MantleAPI/Map/i_route_repository.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <string>
+
+namespace mantle_api
+{
+class MockRouteRepository : public mantle_api::IRouteRepository
+{
+public:
+  MOCK_METHOD(std::weak_ptr<IRoute>,
+              Create,
+              (const std::string& name, const RoutingDefinition& definition),
+              (override));
+
+  MOCK_METHOD(std::weak_ptr<const IRoute>,
+              Get,
+              (const std::string& name),
+              (const override));
+
+  MOCK_METHOD(std::weak_ptr<const IRoute>,
+              Get,
+              (UniqueId id),
+              (const override));
+
+  MOCK_METHOD(bool,
+              Contains,
+              (UniqueId route_id),
+              (const, override));
+
+  MOCK_METHOD(void,
+              Delete,
+              (UniqueId route_id),
+              (override));
+
+  MOCK_METHOD(void,
+              Delete,
+              (const std::string& name),
+              (override));
+
+  MOCK_METHOD(void,
+              Reset,
+              (),
+              (override));
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_MAP_MOCK_ROUTE_REPOSITORY_H
diff --git a/test/MantleAPI/Map/route_test.cc b/test/MantleAPI/Map/route_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b0fd8eaeb8a561af3263abd70d06be223f1542b8
--- /dev/null
+++ b/test/MantleAPI/Map/route_test.cc
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <utility>
+
+#include "MantleAPI/Common/position.h"
+#include "MantleAPI/Map/i_route.h"
+#include "MantleAPI/Map/mock_route.h"
+
+namespace mantle_api
+{
+
+using testing::_;
+using testing::Return;
+
+class RouteTest : public testing::Test
+{
+protected:
+  MockRoute mock_route_;
+  IRoute& route_{mock_route_};
+};
+
+TEST_F(RouteTest, GetLength)
+{
+  EXPECT_CALL(mock_route_, GetLength())
+      .Times(1)
+      .WillOnce(Return(units::length::meter_t{}));
+
+  std::ignore = std::as_const(route_).GetLength();
+}
+
+TEST_F(RouteTest, IsLooped)
+{
+  EXPECT_CALL(mock_route_, IsLooped())
+      .Times(1)
+      .WillOnce(Return(bool{}));
+
+  std::ignore = std::as_const(route_).IsLooped();
+}
+
+TEST_F(RouteTest, ProjectAlongReferenceLine)
+{
+  EXPECT_CALL(mock_route_, ProjectAlongReferenceLine(_, _))
+      .Times(1)
+      .WillOnce(Return(OpenDriveRoadPosition{}));
+
+  std::ignore = std::as_const(route_).ProjectAlongReferenceLine({}, {});
+}
+
+TEST_F(RouteTest, GetOffsetAlongReferenceLine)
+{
+  EXPECT_CALL(mock_route_, GetOffsetAlongReferenceLine(_))
+      .Times(1)
+      .WillOnce(Return(std::optional<units::length::meter_t>{}));
+
+  std::ignore = std::as_const(route_).GetOffsetAlongReferenceLine({});
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Map/routing_definition_test.cc b/test/MantleAPI/Map/routing_definition_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..26367d8e5283c2e923d329b0436f4742f5eef8b0
--- /dev/null
+++ b/test/MantleAPI/Map/routing_definition_test.cc
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include "MantleAPI/Map/routing_definition.h"
+
+#include <gtest/gtest.h>
+#include <units.h>
+#include <sstream>
+
+#include <type_traits>
+
+#include "MantleAPI/Common/vector.h"
+
+namespace mantle_api {
+
+using ::units::literals::operator""_m;
+
+/*******************************************************************************
+ * RouteWaypoint
+ *******************************************************************************/
+static_assert(std::is_aggregate_v<RoutingWaypoint>);
+
+TEST(RoutingWaypointTest, OperatorEqual) {
+  const auto lhs =
+      RoutingWaypoint{Vec3{1_m, 1_m, 1_m}, RoutingStrategy::kFastest};
+  const auto rhs =
+      RoutingWaypoint{Vec3{1_m, 1_m, 1_m}, RoutingStrategy::kFastest};
+
+  ASSERT_EQ(lhs, rhs);
+}
+
+TEST(RoutingWaypointTest, OperatorNotEqual) {
+  const auto lhs =
+      RoutingWaypoint{Vec3{1_m, 1_m, 1_m}, RoutingStrategy::kFastest};
+  const auto rhs =
+      RoutingWaypoint{Vec3{2_m, 2_m, 2_m}, RoutingStrategy::kFastest};
+
+  ASSERT_NE(lhs, rhs);
+}
+
+TEST(RoutingWaypointTest, OutputStreamOperator)
+{
+  const auto routing_waypoint = RoutingWaypoint{Vec3{1_m, 1_m, 1_m}, RoutingStrategy::kFastest};
+
+  auto oss = std::ostringstream{};
+  oss << routing_waypoint;
+
+  ASSERT_EQ(oss.str(), "RoutingWaypoint(.position=Vec3(.x=1 m, .y=1 m, .z=1 m), .routing_strategy=2)");
+}
+
+/*******************************************************************************
+ * RouteDefinition
+ *******************************************************************************/
+static_assert(std::is_aggregate_v<RoutingDefinition>);
+
+TEST(RoutingDefinitionTest, OperatorEqual) {
+  const auto lhs =
+      RoutingDefinition{{{Vec3{1_m, 1_m, 1_m}, RoutingStrategy::kFastest},
+                         {Vec3{2_m, 2_m, 2_m}, RoutingStrategy::kFastest},
+                         {Vec3{3_m, 3_m, 3_m}, RoutingStrategy::kFastest}}};
+  const auto rhs =
+      RoutingDefinition{{{Vec3{1_m, 1_m, 1_m}, RoutingStrategy::kFastest},
+                         {Vec3{2_m, 2_m, 2_m}, RoutingStrategy::kFastest},
+                         {Vec3{3_m, 3_m, 3_m}, RoutingStrategy::kFastest}}};
+
+  ASSERT_EQ(lhs, rhs);
+}
+
+TEST(RoutingDefinitionTest, OperatorNotEqual) 
+{
+  const auto lhs =
+      RoutingDefinition{{{Vec3{1_m, 1_m, 1_m}, RoutingStrategy::kFastest},
+                         {Vec3{2_m, 2_m, 2_m}, RoutingStrategy::kFastest},
+                         {Vec3{3_m, 3_m, 3_m}, RoutingStrategy::kFastest}}};
+  const auto rhs =
+      RoutingDefinition{{{Vec3{1_m, 1_m, 1_m}, RoutingStrategy::kFastest},
+                         {Vec3{2_m, 2_m, 2_m}, RoutingStrategy::kFastest},
+                         {Vec3{3_m, 3_m, 3_m}, RoutingStrategy::kShortest}}};
+
+  ASSERT_NE(lhs, rhs);
+}
+
+TEST(RoutingDefinitionTest, OutputStreamOperatorEmpty)
+{
+  const auto routing_definition = RoutingDefinition{};
+
+  auto oss = std::ostringstream{};
+  oss << routing_definition;
+
+  ASSERT_EQ(oss.str(), "RoutingDefinition()");
+}
+
+TEST(RoutingDefinitionTest, OutputStreamOperatorOneWaypoint)
+{
+  const auto routing_definition = RoutingDefinition{
+      {{Vec3{1_m, 1_m, 1_m}, RoutingStrategy::kFastest}}};
+
+  auto oss = std::ostringstream{};
+  oss << routing_definition;
+
+  ASSERT_EQ(oss.str(), "RoutingDefinition([0]=RoutingWaypoint(.position=Vec3(.x=1 m, .y=1 m, .z=1 m), .routing_strategy=2))");
+}
+
+TEST(RoutingDefinitionTest, OutputStreamOperator)
+{
+  const auto routing_definition = RoutingDefinition{
+      {{Vec3{1_m, 1_m, 1_m}, RoutingStrategy::kFastest},
+       {Vec3{2_m, 2_m, 2_m}, RoutingStrategy::kFastest},
+       {Vec3{3_m, 3_m, 3_m}, RoutingStrategy::kFastest}}};
+
+  auto oss = std::ostringstream{};
+  oss << routing_definition;
+
+  ASSERT_EQ(oss.str(), "RoutingDefinition([0]=RoutingWaypoint(.position=Vec3(.x=1 m, .y=1 m, .z=1 m), .routing_strategy=2), [1]=RoutingWaypoint(.position=Vec3(.x=2 m, .y=2 m, .z=2 m), .routing_strategy=2), [2]=RoutingWaypoint(.position=Vec3(.x=3 m, .y=3 m, .z=3 m), .routing_strategy=2))");
+}
+
+} // namespace mantle_api
diff --git a/test/MantleAPI/Test/test_utils.h b/test/MantleAPI/Test/test_utils.h
deleted file mode 100644
index e858326b8a76376f43656cdef6028a2ed0ee55f3..0000000000000000000000000000000000000000
--- a/test/MantleAPI/Test/test_utils.h
+++ /dev/null
@@ -1,661 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2021-2025, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
- * Copyright (c) 2022 Ansys, Inc.
- * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
- *
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- *******************************************************************************/
-
-//-----------------------------------------------------------------------------
-/** @file  test_utils.h */
-//-----------------------------------------------------------------------------
-
-#pragma once
-
-#include <MantleAPI/Common/i_identifiable.h>
-#include <MantleAPI/Common/position.h>
-#include <MantleAPI/EnvironmentalConditions/road_condition.h>
-#include <MantleAPI/EnvironmentalConditions/weather.h>
-#include <MantleAPI/Execution/i_environment.h>
-#include <MantleAPI/Map/i_coord_converter.h>
-#include <MantleAPI/Map/i_lane_location_query_service.h>
-#include <MantleAPI/Map/lane_definition.h>
-#include <MantleAPI/Traffic/entity_properties.h>
-#include <MantleAPI/Traffic/i_controller_config.h>
-#include <MantleAPI/Traffic/i_controller_repository.h>
-#include <MantleAPI/Traffic/i_entity.h>
-#include <MantleAPI/Traffic/i_entity_repository.h>
-#include <MantleAPI/Traffic/i_traffic_area_service.h>
-#include <MantleAPI/Traffic/i_traffic_area_stream.h>
-#include <MantleAPI/Traffic/i_traffic_swarm_service.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-namespace mantle_api
-{
-class MockGeometryHelper : public mantle_api::IGeometryHelper
-{
-public:
-  MOCK_METHOD(mantle_api::Vec3<units::length::meter_t>, TranslateGlobalPositionLocally, (const Vec3<units::length::meter_t>& global_position, const Orientation3<units::angle::radian_t>& local_orientation, const Vec3<units::length::meter_t>& local_translation), (const override));
-
-  virtual std::vector<Vec3<units::length::meter_t>> TransformPolylinePointsFromWorldToLocal(
-      const std::vector<Vec3<units::length::meter_t>>& polyline_points,
-      const Vec3<units::length::meter_t>& position,
-      const Orientation3<units::angle::radian_t>& orientation) const
-  {
-    // do not transform but return original points
-    std::ignore = position;
-    std::ignore = orientation;
-    return polyline_points;
-  }
-
-  virtual Vec3<units::length::meter_t> TransformPositionFromWorldToLocal(
-      const Vec3<units::length::meter_t>& point_position,
-      const Vec3<units::length::meter_t>& position,
-      const Orientation3<units::angle::radian_t>& orientation) const
-  {
-    // do not transform but return original points
-    std::ignore = position;
-    std::ignore = orientation;
-    return point_position;
-  }
-
-  MOCK_METHOD(bool, AreOrientedSimilarly, (const Orientation3<units::angle::radian_t>& orientation1, const Orientation3<units::angle::radian_t>& orientation2), (const override));
-};
-
-class MockConverter : public mantle_api::ICoordConverter
-{
-public:
-  MOCK_METHOD(mantle_api::Vec3<units::length::meter_t>, Convert, (mantle_api::Position position), (override));
-  MOCK_METHOD(Orientation3<units::angle::radian_t>, GetLaneOrientation, (const OpenDriveLanePosition& open_drive_lane_position), (override));
-  MOCK_METHOD(Orientation3<units::angle::radian_t>, GetRoadOrientation, (const OpenDriveRoadPosition& open_drive_road_position), (override));
-};
-
-class MockVehicle : public mantle_api::IVehicle
-{
-public:
-  MOCK_METHOD(mantle_api::UniqueId, GetUniqueId, (), (const, override));
-
-  void SetName(const std::string& name) override { name_ = name; }
-  const std::string& GetName() const override { return name_; }
-
-  MOCK_METHOD(void, SetPosition, (const mantle_api::Vec3<units::length::meter_t>& inert_pos), (override));
-  MOCK_METHOD(mantle_api::Vec3<units::length::meter_t>, GetPosition, (), (const, override));
-
-  MOCK_METHOD(void, SetVelocity, (const mantle_api::Vec3<units::velocity::meters_per_second_t>& velocity), (override));
-  MOCK_METHOD(mantle_api::Vec3<units::velocity::meters_per_second_t>, GetVelocity, (), (const, override));
-
-  MOCK_METHOD(void, SetAcceleration, (const mantle_api::Vec3<units::acceleration::meters_per_second_squared_t>& acceleration), (override));
-  MOCK_METHOD(mantle_api::Vec3<units::acceleration::meters_per_second_squared_t>, GetAcceleration, (), (const, override));
-
-  MOCK_METHOD(void, SetOrientation, (const mantle_api::Orientation3<units::angle::radian_t>& orientation), (override));
-  MOCK_METHOD(mantle_api::Orientation3<units::angle::radian_t>, GetOrientation, (), (const, override));
-
-  MOCK_METHOD(void, SetOrientationRate, (const mantle_api::Orientation3<units::angular_velocity::radians_per_second_t>& orientation_rate), (override));
-  MOCK_METHOD(mantle_api::Orientation3<units::angular_velocity::radians_per_second_t>, GetOrientationRate, (), (const, override));
-
-  MOCK_METHOD(void,
-              SetOrientationAcceleration,
-              (const mantle_api::Orientation3<units::angular_acceleration::radians_per_second_squared_t>& orientation_acceleration),
-              (override));
-  MOCK_METHOD(mantle_api::Orientation3<units::angular_acceleration::radians_per_second_squared_t>, GetOrientationAcceleration, (), (const, override));
-
-  MOCK_METHOD(void, SetAssignedLaneIds, (const std::vector<std::uint64_t>& ids), (override));
-  MOCK_METHOD(std::vector<std::uint64_t>, GetAssignedLaneIds, (), (const, override));
-
-  MOCK_METHOD(void, SetVisibility, (const EntityVisibilityConfig& visibility), (override));
-  MOCK_METHOD(EntityVisibilityConfig, GetVisibility, (), (const, override));
-
-  void SetProperties(std::unique_ptr<mantle_api::EntityProperties> properties) override { properties_ = std::move(properties); }
-
-  MOCK_METHOD(mantle_api::VehicleProperties*, GetPropertiesImpl, (), (const));
-  mantle_api::VehicleProperties* GetProperties() const override
-  {
-    if (auto* properties = GetPropertiesImpl())
-    {
-      return properties;
-    }
-    return static_cast<mantle_api::VehicleProperties*>(properties_.get());
-  }
-
-  MOCK_METHOD(void, SetSteeringWheelAngle, (units::angle::radian_t steering_wheel_angle), (override));
-  MOCK_METHOD(units::angle::radian_t, GetSteeringWheelAngle, (), (const, override));
-
-private:
-  std::string name_{};
-  std::unique_ptr<mantle_api::EntityProperties> properties_{std::make_unique<mantle_api::VehicleProperties>()};
-};
-
-class MockQueryService : public mantle_api::ILaneLocationQueryService
-{
-public:
-  MOCK_METHOD(Orientation3<units::angle::radian_t>, GetLaneOrientation, (const Vec3<units::length::meter_t>& position), (const override));
-
-  MOCK_METHOD(Vec3<units::length::meter_t>, GetUpwardsShiftedLanePosition, (const Vec3<units::length::meter_t>& position, double upwards_shift, bool allowed_to_leave_lane), (const override));
-
-  MOCK_METHOD(bool, IsPositionOnLane, (const Vec3<units::length::meter_t>& position), (const override));
-
-  MOCK_METHOD(std::vector<UniqueId>, GetLaneIdsAtPosition, (const Vec3<units::length::meter_t>& position), (const override));
-
-  MOCK_METHOD(std::optional<Pose>, FindLanePoseAtDistanceFrom, (const Pose&, units::length::meter_t, Direction), (const, override));
-
-  std::optional<Pose> FindRelativeLanePoseAtDistanceFrom(const Pose& reference_pose_on_lane, int relative_target_lane, units::length::meter_t distance, units::length::meter_t lateral_offset) const override
-  {
-    std::ignore = reference_pose_on_lane;
-    std::ignore = relative_target_lane;
-    std::ignore = distance;
-    std::ignore = lateral_offset;
-    Pose pose{};
-    return pose;
-  }
-
-  std::optional<LaneId> GetRelativeLaneId(const mantle_api::Pose& reference_pose_on_lane, int relative_lane_target) const override
-  {
-    std::ignore = reference_pose_on_lane;
-    std::ignore = relative_lane_target;
-    return 0;
-  }
-
-  MOCK_METHOD(std::optional<units::length::meter_t>,
-              GetLongitudinalLaneDistanceBetweenPositions,
-              (const mantle_api::Vec3<units::length::meter_t>&, const mantle_api::Vec3<units::length::meter_t>&),
-              (const, override));
-
-  MOCK_METHOD(std::optional<Vec3<units::length::meter_t>>,
-              GetPosition,
-              (const Pose&, LateralDisplacementDirection, units::length::meter_t),
-              (const, override));
-
-  MOCK_METHOD(std::optional<Pose>,
-              GetProjectedPoseAtLane,
-              (const mantle_api::Vec3<units::length::meter_t>&, mantle_api::LaneId),
-              (const, override));
-
-  MOCK_METHOD(std::optional<Vec3<units::length::meter_t>>,
-              GetProjectedCenterLinePoint,
-              (const Vec3<units::length::meter_t>&),
-              (const, override));
-
-  MOCK_METHOD(units::length::meter_t, GetLaneHeightAtPosition, (const Vec3<units::length::meter_t>&), (const));
-
-private:
-  MockVehicle test_vehicle_{};
-};
-
-class MockPedestrian : public mantle_api::IPedestrian
-{
-public:
-  MOCK_METHOD(mantle_api::UniqueId, GetUniqueId, (), (const, override));
-
-  void SetName(const std::string& name) override { name_ = name; }
-  const std::string& GetName() const override { return name_; }
-
-  MOCK_METHOD(void, SetPosition, (const mantle_api::Vec3<units::length::meter_t>& inert_pos), (override));
-  MOCK_METHOD(mantle_api::Vec3<units::length::meter_t>, GetPosition, (), (const, override));
-
-  MOCK_METHOD(void, SetVelocity, (const mantle_api::Vec3<units::velocity::meters_per_second_t>& velocity), (override));
-  MOCK_METHOD(mantle_api::Vec3<units::velocity::meters_per_second_t>, GetVelocity, (), (const, override));
-
-  MOCK_METHOD(void, SetAcceleration, (const mantle_api::Vec3<units::acceleration::meters_per_second_squared_t>& acceleration), (override));
-  MOCK_METHOD(mantle_api::Vec3<units::acceleration::meters_per_second_squared_t>, GetAcceleration, (), (const, override));
-
-  MOCK_METHOD(void, SetOrientation, (const mantle_api::Orientation3<units::angle::radian_t>& orientation), (override));
-  MOCK_METHOD(mantle_api::Orientation3<units::angle::radian_t>, GetOrientation, (), (const, override));
-
-  MOCK_METHOD(void, SetOrientationRate, (const mantle_api::Orientation3<units::angular_velocity::radians_per_second_t>& orientation_rate), (override));
-  MOCK_METHOD(mantle_api::Orientation3<units::angular_velocity::radians_per_second_t>, GetOrientationRate, (), (const, override));
-
-  MOCK_METHOD(void,
-              SetOrientationAcceleration,
-              (const mantle_api::Orientation3<units::angular_acceleration::radians_per_second_squared_t>& orientation_acceleration),
-              (override));
-  MOCK_METHOD(mantle_api::Orientation3<units::angular_acceleration::radians_per_second_squared_t>, GetOrientationAcceleration, (), (const, override));
-
-  MOCK_METHOD(void, SetAssignedLaneIds, (const std::vector<std::uint64_t>& ids), (override));
-  MOCK_METHOD(std::vector<std::uint64_t>, GetAssignedLaneIds, (), (const, override));
-
-  MOCK_METHOD(void, SetVisibility, (const EntityVisibilityConfig& visibility), (override));
-  MOCK_METHOD(EntityVisibilityConfig, GetVisibility, (), (const, override));
-
-  void SetProperties(std::unique_ptr<mantle_api::EntityProperties> properties) override { properties_ = std::move(properties); }
-  mantle_api::PedestrianProperties* GetProperties() const override
-  {
-    return static_cast<mantle_api::PedestrianProperties*>(properties_.get());
-  }
-
-private:
-  std::string name_{};
-  std::unique_ptr<mantle_api::EntityProperties> properties_{nullptr};
-};
-
-class MockStaticObject : public mantle_api::IStaticObject
-{
-public:
-  MOCK_METHOD(mantle_api::UniqueId, GetUniqueId, (), (const, override));
-
-  void SetName(const std::string& name) override { name_ = name; }
-  const std::string& GetName() const override { return name_; }
-
-  MOCK_METHOD(void, SetPosition, (const mantle_api::Vec3<units::length::meter_t>& inert_pos), (override));
-  MOCK_METHOD(mantle_api::Vec3<units::length::meter_t>, GetPosition, (), (const, override));
-
-  MOCK_METHOD(void, SetVelocity, (const mantle_api::Vec3<units::velocity::meters_per_second_t>& velocity), (override));
-  MOCK_METHOD(mantle_api::Vec3<units::velocity::meters_per_second_t>, GetVelocity, (), (const, override));
-
-  MOCK_METHOD(void, SetAcceleration, (const mantle_api::Vec3<units::acceleration::meters_per_second_squared_t>& acceleration), (override));
-  MOCK_METHOD(mantle_api::Vec3<units::acceleration::meters_per_second_squared_t>, GetAcceleration, (), (const, override));
-
-  MOCK_METHOD(void, SetOrientation, (const mantle_api::Orientation3<units::angle::radian_t>& orientation), (override));
-  MOCK_METHOD(mantle_api::Orientation3<units::angle::radian_t>, GetOrientation, (), (const, override));
-
-  MOCK_METHOD(void, SetOrientationRate, (const mantle_api::Orientation3<units::angular_velocity::radians_per_second_t>& orientation_rate), (override));
-  MOCK_METHOD(mantle_api::Orientation3<units::angular_velocity::radians_per_second_t>, GetOrientationRate, (), (const, override));
-
-  MOCK_METHOD(void,
-              SetOrientationAcceleration,
-              (const mantle_api::Orientation3<units::angular_acceleration::radians_per_second_squared_t>& orientation_acceleration),
-              (override));
-  MOCK_METHOD(mantle_api::Orientation3<units::angular_acceleration::radians_per_second_squared_t>, GetOrientationAcceleration, (), (const, override));
-
-  MOCK_METHOD(void, SetAssignedLaneIds, (const std::vector<std::uint64_t>& ids), (override));
-  MOCK_METHOD(std::vector<std::uint64_t>, GetAssignedLaneIds, (), (const, override));
-
-  MOCK_METHOD(void, SetVisibility, (const EntityVisibilityConfig& visibility), (override));
-  MOCK_METHOD(EntityVisibilityConfig, GetVisibility, (), (const, override));
-
-  void SetProperties(std::unique_ptr<mantle_api::EntityProperties> properties) override { properties_ = std::move(properties); }
-  MOCK_METHOD(mantle_api::StaticObjectProperties*, GetPropertiesImpl, (), (const));
-
-  mantle_api::StaticObjectProperties* GetProperties() const override
-  {
-    if (auto* properties = GetPropertiesImpl())
-    {
-      return properties;
-    }
-    return static_cast<mantle_api::StaticObjectProperties*>(properties_.get());
-  }
-
-private:
-  std::string name_{};
-  std::unique_ptr<mantle_api::EntityProperties> properties_{nullptr};
-};
-
-class MockEntityRepository : public mantle_api::IEntityRepository
-{
-public:
-  template <typename T>
-  T& RegisterEntity()
-  {
-    auto entity = std::make_unique<T>();
-    auto& entity_ref = entities_.emplace_back(std::move(entity));
-    return *(dynamic_cast<T*>(entity_ref.get()));
-  }
-
-  MockEntityRepository()
-      : test_vehicle_{RegisterEntity<MockVehicle>()},
-        test_pedestrian_{RegisterEntity<MockPedestrian>()},
-        test_static_object_{RegisterEntity<MockStaticObject>()}
-  {
-  }
-
-  MOCK_METHOD(mantle_api::IVehicle&,
-              Create,
-              (const std::string& name, const mantle_api::VehicleProperties& properties),
-              (override));
-
-  mantle_api::IVehicle& Create(mantle_api::UniqueId id,
-                               const std::string& name,
-                               const mantle_api::VehicleProperties& properties) override
-  {
-    std::ignore = id;
-    std::ignore = name;
-    std::ignore = properties;
-    return test_vehicle_;
-  }
-
-  MOCK_METHOD(mantle_api::IPedestrian&,
-              Create,
-              (const std::string& name, const mantle_api::PedestrianProperties& properties),
-              (override));
-
-  mantle_api::IPedestrian& Create(mantle_api::UniqueId id,
-                                  const std::string& name,
-                                  const mantle_api::PedestrianProperties& properties) override
-  {
-    std::ignore = id;
-    std::ignore = name;
-    std::ignore = properties;
-    return test_pedestrian_;
-  }
-
-  mantle_api::IStaticObject& Create(mantle_api::UniqueId id,
-                                    const std::string& name,
-                                    const mantle_api::StaticObjectProperties& properties) override
-  {
-    std::ignore = id;
-    std::ignore = name;
-    std::ignore = properties;
-    return test_static_object_;
-  }
-
-  MOCK_METHOD(mantle_api::IStaticObject&,
-              Create,
-              (const std::string& name, const mantle_api::StaticObjectProperties& properties),
-              ());
-
-  MOCK_METHOD(mantle_api::IEntity*,
-              GetImpl,
-              (const std::string& name),
-              ());
-
-  MOCK_METHOD(mantle_api::IEntity*,
-              GetImpl,
-              (const std::string& name),
-              (const));
-
-  std::optional<std::reference_wrapper<IEntity>> Get(const std::string& name) override
-  {
-    if (auto* entity = GetImpl(name))
-    {
-      return *entity;
-    }
-    return test_vehicle_;
-  }
-
-  std::optional<std::reference_wrapper<const IEntity>> Get(const std::string& name) const override
-  {
-    if (auto* entity = GetImpl(name))
-    {
-      return *entity;
-    }
-    return test_vehicle_;
-  }
-
-  std::optional<std::reference_wrapper<IEntity>> Get(mantle_api::UniqueId id) override
-  {
-    std::ignore = id;
-    return test_vehicle_;
-  }
-
-  std::optional<std::reference_wrapper<const IEntity>> Get(mantle_api::UniqueId id) const override
-  {
-    std::ignore = id;
-    return test_vehicle_;
-  }
-
-  mantle_api::IVehicle& GetHost() override { return test_vehicle_; }
-
-  MOCK_METHOD(std::vector<std::unique_ptr<mantle_api::IEntity>>&,
-              GetEntities,
-              (),
-              (const, override));
-
-  bool Contains(UniqueId id) const override
-  {
-    std::ignore = id;
-    return false;
-  }
-
-  MOCK_METHOD(void, Delete, (UniqueId), (override));
-  MOCK_METHOD(void, Delete, (const std::string&), (override));
-
-  MOCK_METHOD(void,
-              Reset,
-              (),
-              (override));
-
-  void RegisterEntityCreatedCallback(const std::function<void(IEntity&)>& callback) override { std::ignore = callback; }
-  void RegisterEntityDeletedCallback(const std::function<void(const std::string&)>& callback) override { std::ignore = callback; }
-  void RegisterEntityDeletedCallback(const std::function<void(UniqueId)>& callback) override { std::ignore = callback; }
-
-private:
-  std::vector<std::unique_ptr<mantle_api::IEntity>> entities_{};
-  MockVehicle& test_vehicle_;
-  MockPedestrian& test_pedestrian_;
-  MockStaticObject& test_static_object_;
-};
-
-class MockController : public mantle_api::IController
-{
-public:
-  MOCK_METHOD(UniqueId,
-              GetUniqueId,
-              (),
-              (const, override));
-
-  MOCK_METHOD(void,
-              SetName,
-              (const std::string& name),
-              (override));
-
-  MOCK_METHOD(const std::string&,
-              GetName,
-              (),
-              (const, override));
-
-  MOCK_METHOD(void,
-              ChangeState,
-              (mantle_api::IController::LateralState, mantle_api::IController::LongitudinalState),
-              (override));
-};
-
-class MockControllerRepository : public mantle_api::IControllerRepository
-{
-public:
-  MOCK_METHOD(mantle_api::IController&,
-              Create,
-              (std::unique_ptr<IControllerConfig> config),
-              (override));
-
-  MOCK_METHOD(mantle_api::IController&,
-              Create,
-              (UniqueId id, std::unique_ptr<IControllerConfig> config),
-              (override));
-
-  MOCK_METHOD(std::optional<std::reference_wrapper<IController>>,
-              Get,
-              (UniqueId id),
-              (override));
-
-  MOCK_METHOD(bool,
-              Contains,
-              (UniqueId id),
-              (const, override));
-
-  MOCK_METHOD(void,
-              Delete,
-              (UniqueId id),
-              (override));
-
-  MOCK_METHOD(void,
-              Reset,
-              (),
-              (override));
-};
-
-class MockTrafficSwarmService : public mantle_api::ITrafficSwarmService
-{
-public:
-  MOCK_METHOD(std::vector<ITrafficSwarmService::SpawningPosition>,
-              GetAvailableSpawningPoses,
-              (),
-              (const, override));
-
-  MOCK_METHOD(mantle_api::VehicleProperties,
-              GetVehicleProperties,
-              (mantle_api::VehicleClass),
-              (const, override));
-
-  MOCK_METHOD(void,
-              UpdateControllerConfig,
-              (std::unique_ptr<mantle_api::ExternalControllerConfig>&, units::velocity::meters_per_second_t),
-              (override));
-
-  MOCK_METHOD(void,
-              SetSwarmEntitiesCount,
-              (size_t),
-              (override));
-};
-
-class MockTrafficAreaService : public mantle_api::ITrafficAreaService
-{
-public:
-  MOCK_METHOD(std::vector<std::shared_ptr<mantle_api::ITrafficAreaStream>>,
-              CreateTrafficArea,
-              (const mantle_api::RoadRange&),
-              (const, override));
-};
-
-class MockTrafficAreaStream : public mantle_api::ITrafficAreaStream
-{
-public:
-  MOCK_METHOD(units::length::meter_t,
-              GetLength,
-              (),
-              (const, override));
-
-  MOCK_METHOD(bool,
-              Contains,
-              (const mantle_api::ITrafficAreaStream::StreamPosition&),
-              (const, override));
-
-  MOCK_METHOD(const mantle_api::IEntity*,
-              GetEntity,
-              (mantle_api::ITrafficAreaStream::SearchDirection, units::length::meter_t, units::length::meter_t),
-              (const, override));
-
-  MOCK_METHOD(std::optional<mantle_api::Pose>,
-              Convert,
-              (const mantle_api::ITrafficAreaStream::StreamPose&),
-              (const, override));
-
-  MOCK_METHOD(std::optional<mantle_api::ITrafficAreaStream::StreamPose>,
-              Convert,
-              (const mantle_api::Pose&),
-              (const, override));
-};
-
-class MockEnvironment : public mantle_api::IEnvironment
-{
-public:
-  MOCK_METHOD(void,
-              CreateMap,
-              (const std::string& file_path, const mantle_api::MapDetails& map_details, const std::string& map_model_reference),
-              (override)
-
-  );
-
-  MOCK_METHOD(void, AddEntityToController, (mantle_api::IEntity & entity, std::uint64_t controller_id), (override)
-
-  );
-
-  MOCK_METHOD(void, RemoveEntityFromController, (std::uint64_t entity_id, std::uint64_t controller_id), (override));
-
-  MOCK_METHOD(void,
-              UpdateControlStrategies,
-              (std::uint64_t entity_id,
-               std::vector<std::shared_ptr<mantle_api::ControlStrategy>> control_strategies),
-              (override));
-
-  MOCK_METHOD(bool,
-              HasControlStrategyGoalBeenReached,
-              (std::uint64_t entity_id, mantle_api::ControlStrategyType type),
-              (const, override));
-
-  MOCK_METHOD(void,
-              SetWeather,
-              (mantle_api::Weather weather),
-              (override));
-
-  const mantle_api::ILaneLocationQueryService& GetQueryService() const override { return query_service_; }
-
-  mantle_api::ICoordConverter* GetConverter() override { return &converter_; }
-
-  const mantle_api::IGeometryHelper* GetGeometryHelper() const override { return &geometry_helper_; }
-
-  mantle_api::IEntityRepository& GetEntityRepository() override { return entity_repository_; }
-
-  const mantle_api::IEntityRepository& GetEntityRepository() const override { return entity_repository_; }
-
-  MockControllerRepository& GetControllerRepository() override { return controller_repository_; }
-
-  const MockControllerRepository& GetControllerRepository() const override { return controller_repository_; }
-
-  void SetRoadCondition(std::vector<mantle_api::FrictionPatch> friction_patches) override
-  {
-    std::ignore = friction_patches;
-  }
-
-  MOCK_METHOD(void,
-              SetTrafficSignalState,
-              (const std::string& traffic_signal_name, const std::string& traffic_signal_state),
-              (override));
-
-  MOCK_METHOD(void,
-              ExecuteCustomCommand,
-              (const std::vector<std::string>& actors, const std::string& type, const std::string& command),
-              (override));
-
-  MOCK_METHOD(void,
-              SetUserDefinedValue,
-              (const std::string& name, const std::string& value),
-              (override));
-
-  MOCK_METHOD(std::optional<std::string>,
-              GetUserDefinedValue,
-              (const std::string& name),
-              (override));
-
-  MOCK_METHOD(void,
-              SetDateTime,
-              (mantle_api::Time date_time),
-              (override));
-
-  MOCK_METHOD(void,
-              SetVariable,
-              (const std::string& name, const ParameterType& value),
-              (override));
-
-  MOCK_METHOD(std::optional<ParameterType>,
-              GetVariable,
-              (const std::string& name),
-              (const, override));
-
-  mantle_api::Time GetDateTime() override { return {}; }
-
-  MOCK_METHOD(mantle_api::Time, GetSimulationTime, (), (override));
-
-  MOCK_METHOD(void,
-              SetDefaultRoutingBehavior,
-              (mantle_api::DefaultRoutingBehavior default_routing_behavior),
-              (override));
-
-  MOCK_METHOD(void,
-              AssignRoute,
-              (mantle_api::UniqueId entity_id, mantle_api::RouteDefinition route_definition),
-              (override));
-
-  MOCK_METHOD(void,
-              InitTrafficSwarmService,
-              (const mantle_api::TrafficSwarmParameters& parameters),
-              (override));
-
-  MockTrafficSwarmService& GetTrafficSwarmService() override { return traffic_swarm_service_; }
-
-  MockTrafficAreaService& GetTrafficAreaService() override { return traffic_area_service_; }
-
-private:
-  MockQueryService query_service_{};
-  MockEntityRepository entity_repository_{};
-  MockControllerRepository controller_repository_{};
-  MockConverter converter_{};
-  MockGeometryHelper geometry_helper_{};
-  MockTrafficSwarmService traffic_swarm_service_{};
-  MockTrafficAreaService traffic_area_service_{};
-};
-
-}  // namespace mantle_api
diff --git a/test/MantleAPI/Traffic/CMakeLists.txt b/test/MantleAPI/Traffic/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2cb5908731f0208bf4a53047cf842e7da751b70d
--- /dev/null
+++ b/test/MantleAPI/Traffic/CMakeLists.txt
@@ -0,0 +1,20 @@
+################################################################################
+# Copyright (c) 2023-2024 Mercedes-Benz Tech Innovation GmbH
+#
+# This program and the accompanying materials are made available under the terms
+# of the Eclipse Public License 2.0 which is available at
+# https://www.eclipse.org/legal/epl-2.0/
+#
+# SPDX-License-Identifier: EPL-2.0
+################################################################################
+
+add_executable(TrafficTest)
+target_sources(
+  TrafficTest PUBLIC controller_repository_test.cc controller_test.cc entity_properties_test.cc
+                     entity_repository_test.cc entity_test.cc traffic_swarm_service_test.cc
+)
+target_include_directories(TrafficTest PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/test>)
+target_link_libraries(TrafficTest PUBLIC MantleAPI::MantleAPI GTest::gmock_main)
+
+include(GoogleTest)
+gtest_discover_tests(TrafficTest)
diff --git a/test/MantleAPI/Traffic/controller_repository_test.cc b/test/MantleAPI/Traffic/controller_repository_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..238ebf696d72ef030fb0d82781e5dd1f6c1546bf
--- /dev/null
+++ b/test/MantleAPI/Traffic/controller_repository_test.cc
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <memory>
+#include <utility>
+
+#include "MantleAPI/Common/i_identifiable.h"
+#include "MantleAPI/Traffic/mock_controller.h"
+#include "MantleAPI/Traffic/mock_controller_repository.h"
+
+namespace mantle_api
+{
+
+using testing::_;
+using testing::Return;
+
+class ControllerRepositoryTest : public testing::Test
+{
+protected:
+  MockControllerRepository mock_controller_repository_;
+  IControllerRepository& controller_repository_{mock_controller_repository_};
+};
+
+TEST_F(ControllerRepositoryTest, Create)
+{
+  auto mock_controller = std::make_shared<MockController>();
+
+  EXPECT_CALL(mock_controller_repository_, Create(_))
+      .Times(1)
+      .WillOnce(Return(mock_controller));
+
+  std::ignore = controller_repository_.Create(std::make_unique<IControllerConfig>());
+}
+
+TEST_F(ControllerRepositoryTest, Get)
+{
+  auto mock_controller = std::make_shared<MockController>();
+
+  EXPECT_CALL(mock_controller_repository_, Get(_))
+      .Times(1)
+      .WillOnce(Return(mock_controller));
+
+  std::ignore = controller_repository_.Get(UniqueId{0U});
+}
+
+TEST_F(ControllerRepositoryTest, Contains)
+{
+  EXPECT_CALL(std::as_const(mock_controller_repository_), Contains(_))
+      .Times(1)
+      .WillOnce(Return(true));
+
+  EXPECT_TRUE(std::as_const(controller_repository_).Contains(UniqueId{0U}));
+}
+
+TEST_F(ControllerRepositoryTest, Delete)
+{
+  EXPECT_CALL(mock_controller_repository_, Delete(_))
+      .Times(1);
+
+  controller_repository_.Delete(UniqueId{0U});
+}
+
+TEST_F(ControllerRepositoryTest, Reset)
+{
+  EXPECT_CALL(mock_controller_repository_, Reset())
+      .Times(1);
+
+  controller_repository_.Reset();
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Traffic/controller_test.cc b/test/MantleAPI/Traffic/controller_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8cb5244055a575aed11b35b0c6a0bcadc8572a5c
--- /dev/null
+++ b/test/MantleAPI/Traffic/controller_test.cc
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "MantleAPI/Traffic/i_controller.h"
+#include "MantleAPI/Traffic/mock_controller.h"
+
+namespace mantle_api
+{
+
+using testing::_;
+using LateralState = IController::LateralState;
+using LongitudinalState = IController::LongitudinalState;
+
+class ControllerTest : public testing::Test
+{
+protected:
+  MockController mock_controller_;
+  IController& controller_{mock_controller_};
+};
+
+TEST_F(ControllerTest, ChangeState)
+{
+  EXPECT_CALL(mock_controller_, ChangeState(_, _))
+      .Times(1);
+
+  controller_.ChangeState(LateralState::kActivate, LongitudinalState::kActivate);
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Traffic/entity_properties_test.cc b/test/MantleAPI/Traffic/entity_properties_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a57af2dac40aef1d7092345ea9326962137af810
--- /dev/null
+++ b/test/MantleAPI/Traffic/entity_properties_test.cc
@@ -0,0 +1,322 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include "MantleAPI/Traffic/entity_properties.h"
+
+#include <gtest/gtest.h>
+#include <units.h>
+
+#include <type_traits>
+
+#include "MantleAPI/Common/bounding_box.h"
+
+namespace mantle_api
+{
+
+using namespace units::literals;
+
+TEST(EntityPropertiesTest, DefaultConstructed)
+{
+  static_assert(!std::is_default_constructible_v<EntityProperties>);
+  static_assert(std::is_nothrow_destructible_v<EntityProperties>);
+  static_assert(!std::is_copy_constructible_v<EntityProperties>);
+  static_assert(!std::is_copy_assignable_v<EntityProperties>);
+  static_assert(!std::is_move_constructible_v<EntityProperties>);
+  static_assert(!std::is_move_assignable_v<EntityProperties>);
+}
+
+TEST(VehiclePropertiesTest, DefaultConstructed)
+{
+  static_assert(std::is_nothrow_default_constructible_v<VehicleProperties>);
+  static_assert(std::is_nothrow_destructible_v<VehicleProperties>);
+
+  const auto props = VehicleProperties{};
+
+  EXPECT_EQ(props.bounding_box, BoundingBox{});
+  EXPECT_EQ(props.type, EntityType::kVehicle);
+  EXPECT_EQ(props.model, "");
+  const auto empty_map = std::map<std::string, std::string>{};
+  EXPECT_EQ(props.properties, empty_map);
+  EXPECT_EQ(props.mass, 0_kg);
+
+  EXPECT_EQ(props.classification, VehicleClass::kUnknown);
+  EXPECT_EQ(props.performance, Performance{});
+  EXPECT_EQ(props.front_axle, Axle{});
+  EXPECT_EQ(props.rear_axle, Axle{});
+  EXPECT_FALSE(props.is_host);
+  EXPECT_FALSE(props.is_controlled_externally);
+}
+
+TEST(VehiclePropertiesTest, CopyConstructed)
+{
+  static_assert(std::is_copy_constructible_v<VehicleProperties>);
+
+  const auto props = VehicleProperties{BoundingBox{}, "name", {}, 1_kg, VehicleClass::kUnknown, Performance{}, Axle{}, Axle{}, false, false};
+  const auto copy = VehicleProperties{props};
+
+  EXPECT_EQ(copy, props);
+}
+
+TEST(VehiclePropertiesTest, MoveConstructed)
+{
+  static_assert(std::is_nothrow_move_constructible_v<VehicleProperties>);
+
+  auto props = VehicleProperties{BoundingBox{}, "name", {}, 1_kg, VehicleClass::kUnknown, Performance{}, Axle{}, Axle{}, false, false};
+  const auto copy = VehicleProperties{props};
+  const auto move = VehicleProperties{std::move(props)};
+
+  EXPECT_EQ(move, copy);
+}
+
+TEST(VehiclePropertiesTest, ConstructedWithArgs)
+{
+  static_assert(std::is_nothrow_constructible_v<VehicleProperties, BoundingBox, std::string, std::map<std::string, std::string>, units::mass::kilogram_t, VehicleClass, Performance, Axle, Axle, bool, bool>);
+
+  const auto props = VehicleProperties{BoundingBox{}, "name", {}, 1_kg, VehicleClass::kUnknown, Performance{}, Axle{}, Axle{}, false, false};
+
+  EXPECT_EQ(props.bounding_box, BoundingBox{});
+  EXPECT_EQ(props.type, EntityType::kVehicle);
+  EXPECT_EQ(props.model, "name");
+  const auto empty_map = std::map<std::string, std::string>{};
+  EXPECT_EQ(props.properties, empty_map);
+  EXPECT_EQ(props.mass, 1_kg);
+
+  EXPECT_EQ(props.classification, VehicleClass::kUnknown);
+  EXPECT_EQ(props.performance, Performance{});
+  EXPECT_EQ(props.front_axle, Axle{});
+  EXPECT_EQ(props.rear_axle, Axle{});
+  EXPECT_FALSE(props.is_host);
+  EXPECT_FALSE(props.is_controlled_externally);
+}
+
+TEST(VehiclePropertiesTest, CopyAssigned)
+{
+  static_assert(std::is_nothrow_copy_assignable_v<VehicleProperties>);
+
+  const auto props = VehicleProperties{BoundingBox{}, "name", {}, 1_kg, VehicleClass::kUnknown, Performance{}, Axle{}, Axle{}, false, false};
+  auto copy = VehicleProperties{};
+  copy = props;
+
+  EXPECT_EQ(copy, props);
+}
+
+TEST(VehiclePropertiesTest, MoveAssigned)
+{
+  static_assert(std::is_nothrow_move_assignable_v<VehicleProperties>);
+
+  auto props = VehicleProperties{BoundingBox{}, "name", {}, 1_kg, VehicleClass::kUnknown, Performance{}, Axle{}, Axle{}, false, false};
+  const auto copy = VehicleProperties{props};
+  auto move = VehicleProperties{};
+  move = std::move(props);
+
+  EXPECT_EQ(move, copy);
+}
+
+TEST(VehiclePropertiesTest, OperatorEqual)
+{
+  const auto lhs = VehicleProperties{};
+  const auto rhs = VehicleProperties{};
+
+  EXPECT_EQ(lhs, rhs);
+}
+
+TEST(VehiclePropertiesTest, OperatorNotEqual)
+{
+  const auto lhs = VehicleProperties{BoundingBox{}, "name", {}, 1_kg, VehicleClass::kUnknown, Performance{}, Axle{}, Axle{}, false, false};
+  const auto rhs = VehicleProperties{BoundingBox{}, "name", {}, 1_kg, VehicleClass::kUnknown, Performance{}, Axle{}, Axle{}, false, true};
+
+  EXPECT_NE(lhs, rhs);
+}
+
+TEST(PedestrianProperties, DefaultConstructed)
+{
+  static_assert(std::is_nothrow_default_constructible_v<PedestrianProperties>);
+  static_assert(std::is_nothrow_destructible_v<PedestrianProperties>);
+
+  const auto props = PedestrianProperties{};
+
+  EXPECT_EQ(props.bounding_box, BoundingBox{});
+  EXPECT_EQ(props.type, EntityType::kPedestrian);
+  EXPECT_EQ(props.model, "");
+  const auto empty_map = std::map<std::string, std::string>{};
+  EXPECT_EQ(props.properties, empty_map);
+  EXPECT_EQ(props.mass, 0_kg);
+}
+
+TEST(PedestrianProperties, CopyConstructed)
+{
+  static_assert(std::is_copy_constructible_v<PedestrianProperties>);
+
+  const auto props = PedestrianProperties{BoundingBox{}, "name", {}, 1_kg};
+  const auto copy = PedestrianProperties{props};
+
+  EXPECT_EQ(copy, props);
+}
+
+TEST(PedestrianProperties, MoveConstructed)
+{
+  static_assert(std::is_nothrow_move_constructible_v<PedestrianProperties>);
+
+  auto props = PedestrianProperties{BoundingBox{}, "name", {}, 1_kg};
+  const auto copy = PedestrianProperties{props};
+  const auto move = PedestrianProperties{std::move(props)};
+
+  EXPECT_EQ(move, copy);
+}
+
+TEST(PedestrianProperties, ConstructedWithArgs)
+{
+  static_assert(std::is_nothrow_constructible_v<PedestrianProperties, BoundingBox, std::string, std::map<std::string, std::string>, units::mass::kilogram_t>);
+
+  const auto props = PedestrianProperties{BoundingBox{}, "name", {}, 1_kg};
+
+  EXPECT_EQ(props.bounding_box, BoundingBox{});
+  EXPECT_EQ(props.type, EntityType::kPedestrian);
+  EXPECT_EQ(props.model, "name");
+  const auto empty_map = std::map<std::string, std::string>{};
+  EXPECT_EQ(props.properties, empty_map);
+  EXPECT_EQ(props.mass, 1_kg);
+}
+
+TEST(PedestrianProperties, CopyAssigned)
+{
+  static_assert(std::is_nothrow_copy_assignable_v<PedestrianProperties>);
+
+  const auto props = PedestrianProperties{BoundingBox{}, "name", {}, 1_kg};
+  auto copy = PedestrianProperties{};
+  copy = props;
+
+  EXPECT_EQ(copy, props);
+}
+
+TEST(PedestrianProperties, MoveAssigned)
+{
+  static_assert(std::is_nothrow_move_assignable_v<PedestrianProperties>);
+
+  auto props = PedestrianProperties{BoundingBox{}, "name", {}, 1_kg};
+  const auto copy = PedestrianProperties{props};
+  auto move = PedestrianProperties{};
+  move = std::move(props);
+
+  EXPECT_EQ(move, copy);
+}
+
+TEST(PedestrianProperties, OperatorEqual)
+{
+  const auto lhs = PedestrianProperties{};
+  const auto rhs = PedestrianProperties{};
+
+  EXPECT_EQ(lhs, rhs);
+}
+
+TEST(PedestrianProperties, OperatorNotEqual)
+{
+  const auto lhs = PedestrianProperties{BoundingBox{}, "name", {}, 1_kg};
+  const auto rhs = PedestrianProperties{BoundingBox{}, "name", {}, 2_kg};
+
+  EXPECT_NE(lhs, rhs);
+}
+
+TEST(StaticObjectProperties, DefaultConstructed)
+{
+  static_assert(std::is_nothrow_default_constructible_v<StaticObjectProperties>);
+  static_assert(std::is_nothrow_destructible_v<StaticObjectProperties>);
+
+  const auto props = StaticObjectProperties{};
+
+  EXPECT_EQ(props.bounding_box, BoundingBox{});
+  EXPECT_EQ(props.type, EntityType::kStatic);
+  EXPECT_EQ(props.model, "");
+  const auto empty_map = std::map<std::string, std::string>{};
+  EXPECT_EQ(props.properties, empty_map);
+  EXPECT_EQ(props.mass, 0_kg);
+
+  EXPECT_EQ(props.static_object_type, StaticObjectType::kUnknown);
+  EXPECT_EQ(props.vertical_offset, 0_m);
+}
+
+TEST(StaticObjectProperties, CopyConstructed)
+{
+  static_assert(std::is_copy_constructible_v<StaticObjectProperties>);
+
+  const auto props = StaticObjectProperties{BoundingBox{}, "name", {}, 1_kg, StaticObjectType::kUnknown, 1_m};
+  const auto copy = StaticObjectProperties{props};
+
+  EXPECT_EQ(copy, props);
+}
+
+TEST(StaticObjectProperties, MoveConstructed)
+{
+  static_assert(std::is_nothrow_move_constructible_v<StaticObjectProperties>);
+
+  auto props = StaticObjectProperties{BoundingBox{}, "name", {}, 1_kg, StaticObjectType::kUnknown, 1_m};
+  const auto copy = StaticObjectProperties{props};
+  const auto move = StaticObjectProperties{std::move(props)};
+
+  EXPECT_EQ(move, copy);
+}
+
+TEST(StaticObjectProperties, ConstructedWithArgs)
+{
+  static_assert(std::is_nothrow_constructible_v<StaticObjectProperties, BoundingBox, std::string, std::map<std::string, std::string>, units::mass::kilogram_t, StaticObjectType, units::length::meter_t>);
+
+  const auto props = StaticObjectProperties{BoundingBox{}, "name", {}, 1_kg, StaticObjectType::kUnknown, 1_m};
+
+  EXPECT_EQ(props.bounding_box, BoundingBox{});
+  EXPECT_EQ(props.type, EntityType::kStatic);
+  EXPECT_EQ(props.model, "name");
+  const auto empty_map = std::map<std::string, std::string>{};
+  EXPECT_EQ(props.properties, empty_map);
+  EXPECT_EQ(props.mass, 1_kg);
+
+  EXPECT_EQ(props.static_object_type, StaticObjectType::kUnknown);
+  EXPECT_EQ(props.vertical_offset, 1_m);
+}
+
+TEST(StaticObjectProperties, CopyAssigned)
+{
+  static_assert(std::is_nothrow_copy_assignable_v<StaticObjectProperties>);
+
+  const auto props = StaticObjectProperties{BoundingBox{}, "name", {}, 1_kg, StaticObjectType::kUnknown, 1_m};
+  auto copy = StaticObjectProperties{};
+  copy = props;
+
+  EXPECT_EQ(copy, props);
+}
+
+TEST(StaticObjectProperties, MoveAssigned)
+{
+  static_assert(std::is_nothrow_move_assignable_v<StaticObjectProperties>);
+
+  auto props = StaticObjectProperties{BoundingBox{}, "name", {}, 1_kg, StaticObjectType::kUnknown, 1_m};
+  const auto copy = StaticObjectProperties{props};
+  auto move = StaticObjectProperties{};
+  move = std::move(props);
+
+  EXPECT_EQ(move, copy);
+}
+
+TEST(StaticObjectProperties, OperatorEqual)
+{
+  const auto lhs = StaticObjectProperties{};
+  const auto rhs = StaticObjectProperties{};
+
+  EXPECT_EQ(lhs, rhs);
+}
+
+TEST(StaticObjectProperties, OperatorNotEqual)
+{
+  const auto lhs = StaticObjectProperties{BoundingBox{}, "name", {}, 1_kg, StaticObjectType::kUnknown, 1_m};
+  const auto rhs = StaticObjectProperties{BoundingBox{}, "name", {}, 2_kg, StaticObjectType::kUnknown, 1_m};
+
+  EXPECT_NE(lhs, rhs);
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Traffic/entity_repository_test.cc b/test/MantleAPI/Traffic/entity_repository_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..44272449081a3abff2ea30e9a7827ae84e9edfea
--- /dev/null
+++ b/test/MantleAPI/Traffic/entity_repository_test.cc
@@ -0,0 +1,201 @@
+/*******************************************************************************
+ * Copyright (c) 2023, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "MantleAPI/Common/i_identifiable.h"
+#include "MantleAPI/Traffic/entity_properties.h"
+#include "MantleAPI/Traffic/i_entity.h"
+#include "MantleAPI/Traffic/mock_entity.h"
+#include "MantleAPI/Traffic/mock_entity_repository.h"
+
+namespace mantle_api
+{
+using testing::_;
+using testing::An;
+using testing::Return;
+
+class EntityRepositoryTest : public testing::Test
+{
+protected:
+  MockEntityRepository mock_entity_repository_;
+  IEntityRepository& entity_repository_{mock_entity_repository_};
+};
+
+TEST_F(EntityRepositoryTest, CreateVehicle)
+{
+  auto mock_vehicle = std::make_shared<MockVehicle>();
+
+  EXPECT_CALL(mock_entity_repository_, Create(_, An<const VehicleProperties&>()))
+      .Times(1)
+      .WillOnce(Return(mock_vehicle));
+
+  std::ignore = entity_repository_.Create({}, VehicleProperties{});
+}
+
+TEST_F(EntityRepositoryTest, CreatePedestrian)
+{
+  auto mock_pedestrian = std::make_shared<MockPedestrian>();
+
+  EXPECT_CALL(mock_entity_repository_, Create(_, An<const PedestrianProperties&>()))
+      .Times(1)
+      .WillOnce(Return(mock_pedestrian));
+
+  std::ignore = entity_repository_.Create({}, PedestrianProperties{});
+}
+
+TEST_F(EntityRepositoryTest, CreateStaticObject)
+{
+  auto mock_static_object = std::make_shared<MockStaticObject>();
+
+  EXPECT_CALL(mock_entity_repository_, Create(_, An<const StaticObjectProperties&>()))
+      .Times(1)
+      .WillOnce(Return(mock_static_object));
+
+  std::ignore = entity_repository_.Create({}, StaticObjectProperties{});
+}
+
+TEST_F(EntityRepositoryTest, GetHost)
+{
+  auto mock_vehicle = std::make_shared<MockVehicle>();
+
+  EXPECT_CALL(mock_entity_repository_, GetHost())
+      .Times(1)
+      .WillOnce(Return(mock_vehicle));
+
+  std::ignore = entity_repository_.GetHost();
+}
+
+TEST_F(EntityRepositoryTest, GetByName)
+{
+  auto mock_vehicle = std::make_shared<MockVehicle>();
+
+  EXPECT_CALL(mock_entity_repository_, Get(An<const std::string&>()))
+      .Times(1)
+      .WillOnce(Return(mock_vehicle));
+
+  std::ignore = entity_repository_.Get("");
+}
+
+TEST_F(EntityRepositoryTest, GetByNameConst)
+{
+  auto mock_vehicle = std::make_shared<MockVehicle>();
+
+  EXPECT_CALL(std::as_const(mock_entity_repository_), Get(An<const std::string&>()))
+      .Times(1)
+      .WillOnce(Return(mock_vehicle));
+
+  std::ignore = std::as_const(entity_repository_).Get("");
+}
+
+TEST_F(EntityRepositoryTest, GetById)
+{
+  auto mock_vehicle = std::make_shared<MockVehicle>();
+
+  EXPECT_CALL(mock_entity_repository_, Get(An<UniqueId>()))
+      .Times(1)
+      .WillOnce(Return(mock_vehicle));
+
+  std::ignore = entity_repository_.Get(UniqueId{0U});
+}
+
+TEST_F(EntityRepositoryTest, GetByIdConst)
+{
+  auto mock_vehicle = std::make_shared<MockVehicle>();
+
+  EXPECT_CALL(std::as_const(mock_entity_repository_), Get(An<UniqueId>()))
+      .Times(1)
+      .WillOnce(Return(mock_vehicle));
+
+  std::ignore = std::as_const(entity_repository_).Get(UniqueId{0U});
+}
+
+TEST_F(EntityRepositoryTest, Contains)
+{
+  EXPECT_CALL(std::as_const(mock_entity_repository_), Contains(_))
+      .Times(1)
+      .WillOnce(Return(true));
+
+  EXPECT_TRUE(std::as_const(entity_repository_).Contains(UniqueId{0U}));
+}
+
+TEST_F(EntityRepositoryTest, DeleteByName)
+{
+  EXPECT_CALL(mock_entity_repository_, Delete(An<const std::string&>()))
+      .Times(1);
+
+  entity_repository_.Delete("");
+}
+
+TEST_F(EntityRepositoryTest, Reset)
+{
+  EXPECT_CALL(mock_entity_repository_, Reset())
+      .Times(1);
+
+  entity_repository_.Reset();
+}
+
+TEST_F(EntityRepositoryTest, DeleteById)
+{
+  EXPECT_CALL(mock_entity_repository_, Delete(An<UniqueId>()))
+      .Times(1);
+
+  entity_repository_.Delete(UniqueId{0U});
+}
+
+TEST_F(EntityRepositoryTest, GetEntities)
+{
+  auto entities = std::vector<std::weak_ptr<IEntity>>{};
+
+  EXPECT_CALL(mock_entity_repository_, GetEntities())
+      .Times(1)
+      .WillOnce(Return(entities));
+
+  std::ignore = entity_repository_.GetEntities();
+}
+
+TEST_F(EntityRepositoryTest, RegisterEntityCreatedCallback)
+{
+  auto callback = std::function<void(std::weak_ptr<IEntity>)>{};
+
+  EXPECT_CALL(mock_entity_repository_, RegisterEntityCreatedCallback(_))
+      .Times(1);
+
+  entity_repository_.RegisterEntityCreatedCallback(callback);
+}
+
+TEST_F(EntityRepositoryTest, RegisterEntityDeletedCallbackByName)
+{
+  auto callback = std::function<void(const std::string&)>{};
+
+  EXPECT_CALL(mock_entity_repository_, RegisterEntityDeletedCallback(An<const std::function<void(const std::string&)>&>()))
+      .Times(1);
+
+  entity_repository_.RegisterEntityDeletedCallback(callback);
+}
+
+TEST_F(EntityRepositoryTest, RegisterEntityDeletedCallbackById)
+{
+  auto callback = std::function<void(UniqueId)>{};
+
+  EXPECT_CALL(mock_entity_repository_, RegisterEntityDeletedCallback(An<const std::function<void(UniqueId)>&>()))
+      .Times(1);
+
+  entity_repository_.RegisterEntityDeletedCallback(callback);
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Traffic/entity_test.cc b/test/MantleAPI/Traffic/entity_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..79c84f96b6b9126110c4a8566429c16851f95898
--- /dev/null
+++ b/test/MantleAPI/Traffic/entity_test.cc
@@ -0,0 +1,261 @@
+/*******************************************************************************
+ * Copyright (c) 2023, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <tuple>
+#include <utility>
+
+#include "MantleAPI/Traffic/entity_properties.h"
+#include "MantleAPI/Traffic/i_entity.h"
+#include "MantleAPI/Traffic/mock_entity.h"
+
+namespace mantle_api
+{
+
+using testing::_;
+using testing::Return;
+
+/*******************************************************************************
+ * EntityTest
+ *******************************************************************************/
+class EntityTest : public testing::Test
+{
+protected:
+  MockEntity mock_entity_;
+  IEntity& entity_{mock_entity_};
+};
+
+TEST_F(EntityTest, SetPosition)
+{
+  EXPECT_CALL(mock_entity_, SetPosition(_))
+      .Times(1);
+
+  entity_.SetPosition({});
+}
+
+TEST_F(EntityTest, GetPosition)
+{
+  EXPECT_CALL(std::as_const(mock_entity_), GetPosition())
+      .Times(1)
+      .WillOnce(Return(Vec3<units::length::meter_t>{}));
+
+  std::ignore = std::as_const(entity_).GetPosition();
+}
+
+TEST_F(EntityTest, SetVelocity)
+{
+  EXPECT_CALL(mock_entity_, SetVelocity(_))
+      .Times(1);
+
+  entity_.SetVelocity({});
+}
+
+TEST_F(EntityTest, GetVelocity)
+{
+  EXPECT_CALL(std::as_const(mock_entity_), GetVelocity())
+      .Times(1)
+      .WillOnce(Return(Vec3<units::velocity::meters_per_second_t>{}));
+
+  std::ignore = std::as_const(entity_).GetVelocity();
+}
+
+TEST_F(EntityTest, SetAcceleration)
+{
+  EXPECT_CALL(mock_entity_, SetAcceleration(_))
+      .Times(1);
+
+  entity_.SetAcceleration({});
+}
+
+TEST_F(EntityTest, GetAcceleration)
+{
+  EXPECT_CALL(std::as_const(mock_entity_), GetAcceleration())
+      .Times(1)
+      .WillOnce(Return(Vec3<units::acceleration::meters_per_second_squared_t>{}));
+
+  std::ignore = std::as_const(entity_).GetAcceleration();
+}
+
+TEST_F(EntityTest, SetOrientation)
+{
+  EXPECT_CALL(mock_entity_, SetOrientation(_))
+      .Times(1);
+
+  entity_.SetOrientation({});
+}
+
+TEST_F(EntityTest, GetOrientation)
+{
+  EXPECT_CALL(std::as_const(mock_entity_), GetOrientation())
+      .Times(1)
+      .WillOnce(Return(Orientation3<units::angle::radian_t>{}));
+
+  std::ignore = std::as_const(entity_).GetOrientation();
+}
+
+TEST_F(EntityTest, SetOrientationRate)
+{
+  EXPECT_CALL(mock_entity_, SetOrientationRate(_))
+      .Times(1);
+
+  entity_.SetOrientationRate({});
+}
+
+TEST_F(EntityTest, GetOrientationRate)
+{
+  EXPECT_CALL(std::as_const(mock_entity_), GetOrientationRate())
+      .Times(1)
+      .WillOnce(Return(Orientation3<units::angular_velocity::radians_per_second_t>{}));
+
+  std::ignore = std::as_const(entity_).GetOrientationRate();
+}
+
+TEST_F(EntityTest, SetOrientationAcceleration)
+{
+  EXPECT_CALL(mock_entity_, SetOrientationAcceleration(_))
+      .Times(1);
+
+  entity_.SetOrientationAcceleration({});
+}
+
+TEST_F(EntityTest, GetOrientationAcceleration)
+{
+  EXPECT_CALL(std::as_const(mock_entity_), GetOrientationAcceleration())
+      .Times(1)
+      .WillOnce(Return(Orientation3<units::angular_acceleration::radians_per_second_squared_t>{}));
+
+  std::ignore = std::as_const(entity_).GetOrientationAcceleration();
+}
+
+TEST_F(EntityTest, SetProperties)
+{
+  EXPECT_CALL(mock_entity_, SetProperties(_))
+      .Times(1);
+
+  entity_.SetProperties({});
+}
+
+TEST_F(EntityTest, GetProperties)
+{
+  auto properties = VehicleProperties{};
+
+  EXPECT_CALL(std::as_const(mock_entity_), GetProperties())
+      .Times(1)
+      .WillOnce(Return(&properties));
+
+  const auto* result = std::as_const(entity_).GetProperties();
+
+  ASSERT_TRUE(result);
+}
+
+TEST_F(EntityTest, SetAssignedLaneIds)
+{
+  EXPECT_CALL(mock_entity_, SetAssignedLaneIds(_))
+      .Times(1);
+
+  entity_.SetAssignedLaneIds({});
+}
+
+TEST_F(EntityTest, GetAssignedLaneIds)
+{
+  EXPECT_CALL(std::as_const(mock_entity_), GetAssignedLaneIds())
+      .Times(1)
+      .WillOnce(Return(std::vector<mantle_api::UniqueId>{}));
+
+  std::ignore = std::as_const(entity_).GetAssignedLaneIds();
+}
+
+TEST_F(EntityTest, SetVisibility)
+{
+  EXPECT_CALL(mock_entity_, SetVisibility(_))
+      .Times(1);
+
+  entity_.SetVisibility({});
+}
+
+TEST_F(EntityTest, GetVisibility)
+{
+  EXPECT_CALL(std::as_const(mock_entity_), GetVisibility())
+      .Times(1)
+      .WillOnce(Return(EntityVisibilityConfig{}));
+
+  std::ignore = std::as_const(entity_).GetVisibility();
+}
+
+/*******************************************************************************
+ * VehicleTest
+ *******************************************************************************/
+class VehicleTest : public testing::Test
+{
+protected:
+  MockVehicle mock_vehicle_;
+  IVehicle& vehicle_{mock_vehicle_};
+};
+
+TEST_F(VehicleTest, GetProperties)
+{
+  auto properties = VehicleProperties{};
+
+  EXPECT_CALL(std::as_const(mock_vehicle_), GetProperties())
+      .Times(1)
+      .WillOnce(Return(&properties));
+
+  const auto* result = std::as_const(vehicle_).GetProperties();
+
+  ASSERT_TRUE(result);
+}
+
+/*******************************************************************************
+ * PedestrianTest
+ *******************************************************************************/
+class PedestrianTest : public testing::Test
+{
+protected:
+  MockPedestrian mock_pedestrian_;
+  IPedestrian& pedestrian_{mock_pedestrian_};
+};
+
+TEST_F(PedestrianTest, GetProperties)
+{
+  auto properties = PedestrianProperties{};
+
+  EXPECT_CALL(std::as_const(mock_pedestrian_), GetProperties())
+      .Times(1)
+      .WillOnce(Return(&properties));
+
+  const auto* result = std::as_const(pedestrian_).GetProperties();
+
+  ASSERT_TRUE(result);
+}
+
+/*******************************************************************************
+ * StaticObjectTest
+ *******************************************************************************/
+class StaticObjectTest : public testing::Test
+{
+protected:
+  MockStaticObject mock_static_object_;
+  IStaticObject& static_object_{mock_static_object_};
+};
+
+TEST_F(StaticObjectTest, GetProperties)
+{
+  auto properties = StaticObjectProperties{};
+
+  EXPECT_CALL(std::as_const(mock_static_object_), GetProperties())
+      .Times(1)
+      .WillOnce(Return(&properties));
+
+  std::ignore = std::as_const(static_object_).GetProperties();
+}
+
+}  // namespace mantle_api
diff --git a/test/MantleAPI/Traffic/mock_controller.h b/test/MantleAPI/Traffic/mock_controller.h
new file mode 100644
index 0000000000000000000000000000000000000000..e246eeeb0d2fdea2ed6d1ed8aa2c7525da9a7e62
--- /dev/null
+++ b/test/MantleAPI/Traffic/mock_controller.h
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#ifndef MANTLEAPI_TRAFFIC_MOCK_CONTROLLER_H
+#define MANTLEAPI_TRAFFIC_MOCK_CONTROLLER_H
+
+#include <gmock/gmock.h>
+
+#include "MantleAPI/Traffic/i_controller.h"
+
+namespace mantle_api
+{
+
+class MockController : public IController
+{
+public:
+  // IIdentifiable
+  MOCK_METHOD(UniqueId, GetUniqueId, (), (const, override));
+  MOCK_METHOD(void, SetName, (const std::string& name), (override));
+  MOCK_METHOD(const std::string&, GetName, (), (const, override));
+
+  // IController
+  MOCK_METHOD(void, ChangeState, (LateralState lateral_state, LongitudinalState longitudinal_state), (override));
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_TRAFFIC_MOCK_CONTROLLER_H
diff --git a/test/MantleAPI/Traffic/mock_controller_repository.h b/test/MantleAPI/Traffic/mock_controller_repository.h
new file mode 100644
index 0000000000000000000000000000000000000000..7d5b9fbd0b26e6b1c3bf59964bf2b74e3d233589
--- /dev/null
+++ b/test/MantleAPI/Traffic/mock_controller_repository.h
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2023, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#ifndef MANTLEAPI_TRAFFIC_MOCK_CONTROLLER_REPOSITORY_H
+#define MANTLEAPI_TRAFFIC_MOCK_CONTROLLER_REPOSITORY_H
+
+#include <gmock/gmock.h>
+
+#include "MantleAPI/Traffic/i_controller_repository.h"
+
+namespace mantle_api
+{
+
+class MockControllerRepository : public IControllerRepository
+{
+public:
+  MOCK_METHOD(std::weak_ptr<IController>, Create, (std::unique_ptr<IControllerConfig> properties), (override));
+  MOCK_METHOD(std::weak_ptr<IController>, Create, (UniqueId id, std::unique_ptr<IControllerConfig> properties), (override));
+  MOCK_METHOD(std::weak_ptr<IController>, Get, (UniqueId id), (override));
+  MOCK_METHOD(bool, Contains, (UniqueId id), (const, override));
+  MOCK_METHOD(void, Delete, (UniqueId id), (override));
+  MOCK_METHOD(void, Reset, (), (override));
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_TRAFFIC_MOCK_CONTROLLER_REPOSITORY_H
diff --git a/test/MantleAPI/Traffic/mock_entity.h b/test/MantleAPI/Traffic/mock_entity.h
new file mode 100644
index 0000000000000000000000000000000000000000..da0be33ba07b84ae26fb8d5664c479da4704af4a
--- /dev/null
+++ b/test/MantleAPI/Traffic/mock_entity.h
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * Copyright (c) 2023, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#ifndef MANTLEAPI_TRAFFIC_MOCK_ENTITY_H
+#define MANTLEAPI_TRAFFIC_MOCK_ENTITY_H
+
+#include <gmock/gmock.h>
+
+#include <memory>
+
+#include "MantleAPI/Map/i_route.h"
+#include "MantleAPI/Traffic/i_entity.h"
+
+namespace mantle_api
+{
+
+class MockEntity : public IEntity
+{
+public:
+  // IIdentifiable
+  MOCK_METHOD(UniqueId, GetUniqueId, (), (const, override));
+
+  MOCK_METHOD(void, SetName, (const std::string& name), (override));
+
+  MOCK_METHOD(const std::string&, GetName, (), (const, override));
+
+  // IEntity
+  MOCK_METHOD(void, SetPosition, (const Vec3<units::length::meter_t>& inert_pos), (override));
+  MOCK_METHOD(Vec3<units::length::meter_t>, GetPosition, (), (const, override));
+
+  MOCK_METHOD(void, SetVelocity, (const Vec3<units::velocity::meters_per_second_t>& velocity), (override));
+  MOCK_METHOD(Vec3<units::velocity::meters_per_second_t>, GetVelocity, (), (const, override));
+
+  MOCK_METHOD(void, SetAcceleration, (const Vec3<units::acceleration::meters_per_second_squared_t>& acceleration), (override));
+  MOCK_METHOD(Vec3<units::acceleration::meters_per_second_squared_t>, GetAcceleration, (), (const, override));
+
+  MOCK_METHOD(void, SetOrientation, (const Orientation3<units::angle::radian_t>& orientation), (override));
+  MOCK_METHOD(Orientation3<units::angle::radian_t>, GetOrientation, (), (const, override));
+
+  MOCK_METHOD(void, SetOrientationRate, (const Orientation3<units::angular_velocity::radians_per_second_t>& orientation_rate), (override));
+  MOCK_METHOD(Orientation3<units::angular_velocity::radians_per_second_t>, GetOrientationRate, (), (const, override));
+
+  MOCK_METHOD(void, SetOrientationAcceleration, (const Orientation3<units::angular_acceleration::radians_per_second_squared_t>& orientation_acceleration), (override));
+  MOCK_METHOD(Orientation3<units::angular_acceleration::radians_per_second_squared_t>, GetOrientationAcceleration, (), (const, override));
+
+  MOCK_METHOD(void, SetProperties, (std::unique_ptr<EntityProperties> properties), (override));
+  MOCK_METHOD(EntityProperties*, GetProperties, (), (const, override));
+
+  MOCK_METHOD(void, SetAssignedLaneIds, (const std::vector<mantle_api::UniqueId>& assigned_lane_ids), (override));
+  MOCK_METHOD(std::vector<mantle_api::UniqueId>, GetAssignedLaneIds, (), (const, override));
+
+  MOCK_METHOD(void, SetVisibility, (const EntityVisibilityConfig& visibility), (override));
+  MOCK_METHOD(EntityVisibilityConfig, GetVisibility, (), (const, override));
+
+  MOCK_METHOD(void, SetRoute, (const std::weak_ptr<const IRoute>& route), (override));
+  MOCK_METHOD(std::weak_ptr<const IRoute>, GetRoute, (), (const, override));
+};
+
+class MockVehicle : public IVehicle
+{
+public:
+  // IIdentifiable
+  MOCK_METHOD(UniqueId, GetUniqueId, (), (const, override));
+
+  MOCK_METHOD(void, SetName, (const std::string& name), (override));
+
+  MOCK_METHOD(const std::string&, GetName, (), (const, override));
+
+  // IEntity
+  MOCK_METHOD(void, SetPosition, (const Vec3<units::length::meter_t>& inert_pos), (override));
+  MOCK_METHOD(Vec3<units::length::meter_t>, GetPosition, (), (const, override));
+
+  MOCK_METHOD(void, SetVelocity, (const Vec3<units::velocity::meters_per_second_t>& velocity), (override));
+  MOCK_METHOD(Vec3<units::velocity::meters_per_second_t>, GetVelocity, (), (const, override));
+
+  MOCK_METHOD(void, SetAcceleration, (const Vec3<units::acceleration::meters_per_second_squared_t>& acceleration), (override));
+  MOCK_METHOD(Vec3<units::acceleration::meters_per_second_squared_t>, GetAcceleration, (), (const, override));
+
+  MOCK_METHOD(void, SetOrientation, (const Orientation3<units::angle::radian_t>& orientation), (override));
+  MOCK_METHOD(Orientation3<units::angle::radian_t>, GetOrientation, (), (const, override));
+
+  MOCK_METHOD(void, SetOrientationRate, (const Orientation3<units::angular_velocity::radians_per_second_t>& orientation_rate), (override));
+  MOCK_METHOD(Orientation3<units::angular_velocity::radians_per_second_t>, GetOrientationRate, (), (const, override));
+
+  MOCK_METHOD(void, SetOrientationAcceleration, (const Orientation3<units::angular_acceleration::radians_per_second_squared_t>& orientation_acceleration), (override));
+  MOCK_METHOD(Orientation3<units::angular_acceleration::radians_per_second_squared_t>, GetOrientationAcceleration, (), (const, override));
+
+  MOCK_METHOD(void, SetProperties, (std::unique_ptr<EntityProperties> properties), (override));
+  // MOCK_METHOD(EntityProperties*, GetProperties, (), (const, override));
+
+  MOCK_METHOD(void, SetAssignedLaneIds, (const std::vector<mantle_api::UniqueId>& assigned_lane_ids), (override));
+  MOCK_METHOD(std::vector<mantle_api::UniqueId>, GetAssignedLaneIds, (), (const, override));
+
+  MOCK_METHOD(void, SetVisibility, (const EntityVisibilityConfig& visibility), (override));
+  MOCK_METHOD(EntityVisibilityConfig, GetVisibility, (), (const, override));
+
+  MOCK_METHOD(void, SetRoute, (const std::weak_ptr<const IRoute>& route), (override));
+  MOCK_METHOD(std::weak_ptr<const IRoute>, GetRoute, (), (const, override));
+
+  // IVehicle
+  MOCK_METHOD(VehicleProperties*, GetProperties, (), (const, override));
+
+  MOCK_METHOD(void, SetSteeringWheelAngle, (units::angle::radian_t steering_wheel_angle), (override));
+  MOCK_METHOD(units::angle::radian_t, GetSteeringWheelAngle, (), (const, override));
+};
+
+class MockPedestrian : public IPedestrian
+{
+public:
+  // IIdentifiable
+  MOCK_METHOD(UniqueId, GetUniqueId, (), (const, override));
+
+  MOCK_METHOD(void, SetName, (const std::string& name), (override));
+
+  MOCK_METHOD(const std::string&, GetName, (), (const, override));
+
+  // IEntity
+  MOCK_METHOD(void, SetPosition, (const Vec3<units::length::meter_t>& inert_pos), (override));
+  MOCK_METHOD(Vec3<units::length::meter_t>, GetPosition, (), (const, override));
+
+  MOCK_METHOD(void, SetVelocity, (const Vec3<units::velocity::meters_per_second_t>& velocity), (override));
+  MOCK_METHOD(Vec3<units::velocity::meters_per_second_t>, GetVelocity, (), (const, override));
+
+  MOCK_METHOD(void, SetAcceleration, (const Vec3<units::acceleration::meters_per_second_squared_t>& acceleration), (override));
+  MOCK_METHOD(Vec3<units::acceleration::meters_per_second_squared_t>, GetAcceleration, (), (const, override));
+
+  MOCK_METHOD(void, SetOrientation, (const Orientation3<units::angle::radian_t>& orientation), (override));
+  MOCK_METHOD(Orientation3<units::angle::radian_t>, GetOrientation, (), (const, override));
+
+  MOCK_METHOD(void, SetOrientationRate, (const Orientation3<units::angular_velocity::radians_per_second_t>& orientation_rate), (override));
+  MOCK_METHOD(Orientation3<units::angular_velocity::radians_per_second_t>, GetOrientationRate, (), (const, override));
+
+  MOCK_METHOD(void, SetOrientationAcceleration, (const Orientation3<units::angular_acceleration::radians_per_second_squared_t>& orientation_acceleration), (override));
+  MOCK_METHOD(Orientation3<units::angular_acceleration::radians_per_second_squared_t>, GetOrientationAcceleration, (), (const, override));
+
+  MOCK_METHOD(void, SetProperties, (std::unique_ptr<EntityProperties> properties), (override));
+  // MOCK_METHOD(EntityProperties*, GetProperties, (), (const, override));
+
+  MOCK_METHOD(void, SetAssignedLaneIds, (const std::vector<mantle_api::UniqueId>& assigned_lane_ids), (override));
+  MOCK_METHOD(std::vector<mantle_api::UniqueId>, GetAssignedLaneIds, (), (const, override));
+
+  MOCK_METHOD(void, SetVisibility, (const EntityVisibilityConfig& visibility), (override));
+  MOCK_METHOD(EntityVisibilityConfig, GetVisibility, (), (const, override));
+
+  MOCK_METHOD(void, SetRoute, (const std::weak_ptr<const IRoute>& route), (override));
+  MOCK_METHOD(std::weak_ptr<const IRoute>, GetRoute, (), (const, override));
+
+  // IPedestrian
+  MOCK_METHOD(PedestrianProperties*, GetProperties, (), (const, override));
+};
+
+class MockStaticObject : public IStaticObject
+{
+public:
+  // IIdentifiable
+  MOCK_METHOD(UniqueId, GetUniqueId, (), (const, override));
+
+  MOCK_METHOD(void, SetName, (const std::string& name), (override));
+
+  MOCK_METHOD(const std::string&, GetName, (), (const, override));
+
+  // IEntity
+  MOCK_METHOD(void, SetPosition, (const Vec3<units::length::meter_t>& inert_pos), (override));
+  MOCK_METHOD(Vec3<units::length::meter_t>, GetPosition, (), (const, override));
+
+  MOCK_METHOD(void, SetVelocity, (const Vec3<units::velocity::meters_per_second_t>& velocity), (override));
+  MOCK_METHOD(Vec3<units::velocity::meters_per_second_t>, GetVelocity, (), (const, override));
+
+  MOCK_METHOD(void, SetAcceleration, (const Vec3<units::acceleration::meters_per_second_squared_t>& acceleration), (override));
+  MOCK_METHOD(Vec3<units::acceleration::meters_per_second_squared_t>, GetAcceleration, (), (const, override));
+
+  MOCK_METHOD(void, SetOrientation, (const Orientation3<units::angle::radian_t>& orientation), (override));
+  MOCK_METHOD(Orientation3<units::angle::radian_t>, GetOrientation, (), (const, override));
+
+  MOCK_METHOD(void, SetOrientationRate, (const Orientation3<units::angular_velocity::radians_per_second_t>& orientation_rate), (override));
+  MOCK_METHOD(Orientation3<units::angular_velocity::radians_per_second_t>, GetOrientationRate, (), (const, override));
+
+  MOCK_METHOD(void, SetOrientationAcceleration, (const Orientation3<units::angular_acceleration::radians_per_second_squared_t>& orientation_acceleration), (override));
+  MOCK_METHOD(Orientation3<units::angular_acceleration::radians_per_second_squared_t>, GetOrientationAcceleration, (), (const, override));
+
+  MOCK_METHOD(void, SetProperties, (std::unique_ptr<EntityProperties> properties), (override));
+  // MOCK_METHOD(EntityProperties*, GetProperties, (), (const, override));
+
+  MOCK_METHOD(void, SetAssignedLaneIds, (const std::vector<mantle_api::UniqueId>& assigned_lane_ids), (override));
+  MOCK_METHOD(std::vector<mantle_api::UniqueId>, GetAssignedLaneIds, (), (const, override));
+
+  MOCK_METHOD(void, SetVisibility, (const EntityVisibilityConfig& visibility), (override));
+  MOCK_METHOD(EntityVisibilityConfig, GetVisibility, (), (const, override));
+
+  MOCK_METHOD(void, SetRoute, (const std::weak_ptr<const IRoute>& route), (override));
+  MOCK_METHOD(std::weak_ptr<const IRoute>, GetRoute, (), (const, override));
+
+  // IStaticObject
+  MOCK_METHOD(StaticObjectProperties*, GetProperties, (), (const, override));
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_TRAFFIC_MOCK_ENTITY_H
diff --git a/test/MantleAPI/Traffic/mock_entity_repository.h b/test/MantleAPI/Traffic/mock_entity_repository.h
new file mode 100644
index 0000000000000000000000000000000000000000..d4683a1ed6bbb4303764ebd4a600cbc1f185f3fe
--- /dev/null
+++ b/test/MantleAPI/Traffic/mock_entity_repository.h
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2023, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#ifndef MANTLEAPI_TRAFFIC_MOCK_ENTITY_REPOSITORY_H
+#define MANTLEAPI_TRAFFIC_MOCK_ENTITY_REPOSITORY_H
+
+#include <gmock/gmock.h>
+
+#include "MantleAPI/Traffic/i_entity_repository.h"
+
+namespace mantle_api
+{
+
+class MockEntityRepository : public IEntityRepository
+{
+public:
+  MOCK_METHOD(std::weak_ptr<IVehicle>, Create, (const std::string& name, const VehicleProperties& properties), (override));
+  MOCK_METHOD(std::weak_ptr<IVehicle>, Create, (UniqueId id, const std::string& name, const VehicleProperties& properties), (override));
+  MOCK_METHOD(std::weak_ptr<IPedestrian>, Create, (const std::string& name, const PedestrianProperties& properties), (override));
+  MOCK_METHOD(std::weak_ptr<IPedestrian>, Create, (UniqueId id, const std::string& name, const PedestrianProperties& properties), (override));
+  MOCK_METHOD(std::weak_ptr<IStaticObject>, Create, (const std::string& name, const StaticObjectProperties& properties), (override));
+  MOCK_METHOD(std::weak_ptr<IStaticObject>, Create, (UniqueId id, const std::string& name, const StaticObjectProperties& properties), (override));
+  MOCK_METHOD(std::weak_ptr<IVehicle>, GetHost, (), (override));
+  MOCK_METHOD(std::weak_ptr<IEntity>, Get, (const std::string& name), (override));
+  MOCK_METHOD(std::weak_ptr<const IEntity>, Get, (const std::string& name), (const, override));
+  MOCK_METHOD(std::weak_ptr<IEntity>, Get, (UniqueId id), (override));
+  MOCK_METHOD(std::weak_ptr<const IEntity>, Get, (UniqueId id), (const, override));
+  MOCK_METHOD(bool, Contains, (UniqueId id), (const, override));
+  MOCK_METHOD(void, Delete, (const std::string& name), (override));
+  MOCK_METHOD(void, Delete, (UniqueId id), (override));
+  MOCK_METHOD(void, Reset, (), (override));
+  MOCK_METHOD(std::vector<std::weak_ptr<IEntity>>, GetEntities, (), (const, override));
+  MOCK_METHOD(void, RegisterEntityCreatedCallback, (const std::function<void(std::weak_ptr<IEntity>)>& callback), (override));
+  MOCK_METHOD(void, RegisterEntityDeletedCallback, (const std::function<void(const std::string&)>& callback), (override));
+  MOCK_METHOD(void, RegisterEntityDeletedCallback, (const std::function<void(UniqueId)>& callback), (override));
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_TRAFFIC_MOCK_ENTITY_REPOSITORY_H
diff --git a/test/MantleAPI/Traffic/mock_traffic_area_service.h b/test/MantleAPI/Traffic/mock_traffic_area_service.h
new file mode 100644
index 0000000000000000000000000000000000000000..a97cbaf48e91d4522d0800eb7a7500bf78c79ffb
--- /dev/null
+++ b/test/MantleAPI/Traffic/mock_traffic_area_service.h
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2025, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#ifndef MANTLEAPI_TRAFFIC_MOCK_TRAFFIC_AREA_SERVICE_H
+#define MANTLEAPI_TRAFFIC_MOCK_TRAFFIC_AREA_SERVICE_H
+
+#include <gmock/gmock.h>
+
+#include "MantleAPI/Traffic/i_traffic_area_service.h"
+
+namespace mantle_api
+{
+class MockTrafficAreaService : public ITrafficAreaService
+{
+public:
+  MOCK_METHOD(TrafficArea, CreateTrafficArea, (const RoadRange& road_range), (const, override));
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_TRAFFIC_MOCK_TRAFFIC_AREA_SERVICE_H
diff --git a/test/MantleAPI/Traffic/mock_traffic_swarm_service.h b/test/MantleAPI/Traffic/mock_traffic_swarm_service.h
new file mode 100644
index 0000000000000000000000000000000000000000..56b7adfaf81d13d860b124ed2d99ad1f5bc2633e
--- /dev/null
+++ b/test/MantleAPI/Traffic/mock_traffic_swarm_service.h
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#ifndef MANTLEAPI_TRAFFIC_MOCK_TRAFFIC_SWARM_SERVICE_H
+#define MANTLEAPI_TRAFFIC_MOCK_TRAFFIC_SWARM_SERVICE_H
+
+#include <gmock/gmock.h>
+#include <units.h>
+
+#include <cstddef>
+#include <memory>
+#include <vector>
+
+#include "MantleAPI/Traffic/entity_properties.h"
+#include "MantleAPI/Traffic/i_controller_config.h"
+#include "MantleAPI/Traffic/i_traffic_swarm_service.h"
+
+namespace mantle_api
+{
+class MockTrafficSwarmService : public ITrafficSwarmService
+{
+public:
+  MOCK_METHOD(std::vector<SpawningPosition>, GetAvailableSpawningPoses, (), (const, override));
+  MOCK_METHOD(mantle_api::VehicleProperties, GetVehicleProperties, (mantle_api::VehicleClass vehicle_class), (const, override));
+  MOCK_METHOD(void, UpdateControllerConfig, (std::unique_ptr<mantle_api::ExternalControllerConfig> & config, units::velocity::meters_per_second_t speed), (override));
+  MOCK_METHOD(void, SetSwarmEntitiesCount, (std::size_t count), (override));
+};
+
+}  // namespace mantle_api
+
+#endif  // MANTLEAPI_TRAFFIC_MOCK_TRAFFIC_SWARM_SERVICE_H
diff --git a/test/MantleAPI/Traffic/traffic_swarm_service_test.cc b/test/MantleAPI/Traffic/traffic_swarm_service_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9ddb2f535cdb345942eb6763107652c09662a7f5
--- /dev/null
+++ b/test/MantleAPI/Traffic/traffic_swarm_service_test.cc
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2024, Mercedes-Benz Tech Innovation GmbH
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <units.h>
+
+#include "MantleAPI/Traffic/i_traffic_swarm_service.h"
+#include "MantleAPI/Traffic/mock_traffic_swarm_service.h"
+
+namespace mantle_api
+{
+
+using testing::_;
+using units::literals::operator""_mps;
+
+class TrafficSwarmServiceTest : public testing::Test
+{
+protected:
+  MockTrafficSwarmService mock_traffic_swarm_service_;
+  ITrafficSwarmService& traffic_swarm_service_{mock_traffic_swarm_service_};
+};
+
+TEST_F(TrafficSwarmServiceTest, GetAvailableSpawningPoses)
+{
+  EXPECT_CALL(mock_traffic_swarm_service_, GetAvailableSpawningPoses())
+      .Times(1);
+
+  std::ignore = traffic_swarm_service_.GetAvailableSpawningPoses();
+}
+
+TEST_F(TrafficSwarmServiceTest, GetVehicleProperties)
+{
+  EXPECT_CALL(mock_traffic_swarm_service_, GetVehicleProperties(_))
+      .Times(1);
+
+  std::ignore = traffic_swarm_service_.GetVehicleProperties(VehicleClass::kSmallCar);
+}
+
+TEST_F(TrafficSwarmServiceTest, UpdateControllerConfig)
+{
+  EXPECT_CALL(mock_traffic_swarm_service_, UpdateControllerConfig(_, _))
+      .Times(1);
+
+  auto config = std::make_unique<ExternalControllerConfig>();
+  static constexpr auto kSpeed = 10.0_mps;
+
+  traffic_swarm_service_.UpdateControllerConfig(config, kSpeed);
+}
+
+TEST_F(TrafficSwarmServiceTest, SetSwarmEntitiesCount)
+{
+  EXPECT_CALL(mock_traffic_swarm_service_, SetSwarmEntitiesCount(_))
+      .Times(1);
+
+  static constexpr auto kCount = 10U;
+
+  traffic_swarm_service_.SetSwarmEntitiesCount(kCount);
+}
+
+}  // namespace mantle_api
diff --git a/test/interface_test.cpp b/test/interface_test.cpp
deleted file mode 100644
index f22d8eddbe30ab667cc67b0ea92ec545582eca94..0000000000000000000000000000000000000000
--- a/test/interface_test.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2021-2024, Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
- *
- * This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License 2.0
- * which is available at https://www.eclipse.org/legal/epl-2.0/
- *
- * SPDX-License-Identifier: EPL-2.0
- *******************************************************************************/
-
-//-----------------------------------------------------------------------------
-/** @file  interface_test.cpp */
-//-----------------------------------------------------------------------------
-
-#include <units.h>
-
-#include "MantleAPI/Common/position.h"
-#include "MantleAPI/Map/i_coord_converter.h"
-#include "MantleAPI/Test/test_utils.h"
-#include "MantleAPI/Traffic/entity_properties.h"
-#include "MantleAPI/Traffic/i_entity.h"
-#include "MantleAPI/Traffic/i_entity_repository.h"
-
-TEST(InterfaceTest, GivenTeleportAction_When_ThenHostVehicleIsPlaced)
-{
-  using namespace units::literals;
-
-  mantle_api::Position inert_pos{};
-  inert_pos = mantle_api::OpenDriveRoadPosition{"0", 0_m, 0_m};
-  mantle_api::MockEnvironment env{};
-  env.CreateMap("dummy_map_path", {}, "");
-
-  mantle_api::VehicleProperties vehicle_properties;
-  vehicle_properties.is_host = true;
-  vehicle_properties.model = "G12";
-
-  auto& repo = env.GetEntityRepository();
-
-  mantle_api::MockVehicle mock_vehicle{};
-  ON_CALL(dynamic_cast<mantle_api::MockEntityRepository&>(repo), Create(testing::_, vehicle_properties))
-      .WillByDefault(testing::ReturnRef(mock_vehicle));
-
-  auto& host_vehicle = repo.Create("host", vehicle_properties);
-  auto* converter = env.GetConverter();
-  auto world_pos = converter->Convert(inert_pos);
-  host_vehicle.SetPosition(world_pos);
-  host_vehicle.SetVisibility(mantle_api::EntityVisibilityConfig{true, false, true, {"radar"}});
-}