diff --git a/Modules/ROI/include/mitkROI.h b/Modules/ROI/include/mitkROI.h
index 92e60cc288..0e76d25c22 100644
--- a/Modules/ROI/include/mitkROI.h
+++ b/Modules/ROI/include/mitkROI.h
@@ -1,80 +1,104 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #ifndef mitkROI_h
 #define mitkROI_h
 
 #include <mitkBaseData.h>
 #include <MitkROIExports.h>
 
 namespace mitk
 {
   class MITKROI_EXPORT ROI : public BaseData
   {
   public:
-    struct MITKROI_EXPORT Element : IPropertyOwner
+    class MITKROI_EXPORT Element : public IPropertyOwner
     {
+    public:
+      using PointsType = std::map<TimeStepType, Point3D>;
+      using PropertyListsType = std::map<TimeStepType, PropertyList::Pointer>;
+
       Element();
+      explicit Element(unsigned int id);
       ~Element() = default;
 
       BaseProperty::ConstPointer GetConstProperty(const std::string& propertyKey, const std::string& contextName = "", bool fallBackOnDefaultContext = true) const override;
       std::vector<std::string> GetPropertyKeys(const std::string& contextName = "", bool includeDefaultContext = false) const override;
       std::vector<std::string> GetPropertyContextNames() const override;
 
       BaseProperty* GetNonConstProperty(const std::string& propertyKey, const std::string& contextName = "", bool fallBackOnDefaultContext = true) override;
       void SetProperty(const std::string& propertyKey, BaseProperty* property, const std::string& contextName = "", bool fallBackOnDefaultContext = false) override;
       void RemoveProperty(const std::string& propertyKey, const std::string& contextName = "", bool fallBackOnDefaultContext = false) override;
 
-      unsigned int ID;
-      Point3D Min;
-      Point3D Max;
-      PropertyList::Pointer Properties;
+      unsigned int GetID() const;
+      void SetID(unsigned int id);
+
+      bool HasTimeStep(TimeStepType t) const;
+
+      Point3D GetMin(TimeStepType t = 0) const;
+      void SetMin(const Point3D& min, TimeStepType t = 0);
+
+      Point3D GetMax(TimeStepType t = 0) const;
+      void SetMax(const Point3D& max, TimeStepType t = 0);
+
+      PropertyList* GetDefaultProperties() const;
+      void SetDefaultProperties(PropertyList* properties);
+
+      PropertyList* GetProperties(TimeStepType t = 0) const;
+      void SetProperties(PropertyList* properties, TimeStepType t = 0);
+
+    private:
+      unsigned int m_ID;
+      PointsType m_Min;
+      PointsType m_Max;
+      PropertyList::Pointer m_DefaultProperties;
+      PropertyListsType m_Properties;
     };
 
     mitkClassMacro(ROI, BaseData)
     itkFactorylessNewMacro(Self)
     itkCloneMacro(Self)
 
-    using ElementsType = std::vector<Element>;
+    using ElementsType = std::map<unsigned int, Element>;
     using Iterator = ElementsType::iterator;
     using ConstIterator = ElementsType::const_iterator;
 
     size_t GetNumberOfElements() const;
-    size_t AddElement(const Element& element);
+    void AddElement(const Element& element);
 
-    const Element* GetElement(size_t index) const;
-    Element* GetElement(size_t index);
+    const Element& GetElement(unsigned int id) const;
+    Element& GetElement(unsigned int id);
 
     ConstIterator begin() const;
     ConstIterator end() const;
 
     Iterator begin();
     Iterator end();
 
     void SetRequestedRegionToLargestPossibleRegion() override;
     bool RequestedRegionIsOutsideOfTheBufferedRegion() override;
     bool VerifyRequestedRegion() override;
     void SetRequestedRegion(const itk::DataObject* data) override;
 
   protected:
     mitkCloneMacro(Self)
 
     ROI();
     ROI(const Self& other);
     ~ROI() override;
 
   private:
     ElementsType m_Elements;
   };
 }
 
 #endif
diff --git a/Modules/ROI/src/mitkROI.cpp b/Modules/ROI/src/mitkROI.cpp
index 67f0540aa8..7243726046 100644
--- a/Modules/ROI/src/mitkROI.cpp
+++ b/Modules/ROI/src/mitkROI.cpp
@@ -1,120 +1,282 @@
 /*============================================================================
 
 The Medical Imaging Interaction Toolkit (MITK)
 
 Copyright (c) German Cancer Research Center (DKFZ)
 All rights reserved.
 
 Use of this source code is governed by a 3-clause BSD license that can be
 found in the LICENSE file.
 
 ============================================================================*/
 
 #include <mitkROI.h>
 
 mitk::ROI::Element::Element()
-  : Properties(PropertyList::New())
+  : Element(0)
 {
 }
 
+mitk::ROI::Element::Element(unsigned int id)
+  : m_ID(id),
+    m_DefaultProperties(PropertyList::New())
+{
+}
+
+unsigned int mitk::ROI::Element::GetID() const
+{
+  return m_ID;
+}
+
+void mitk::ROI::Element::SetID(unsigned int id)
+{
+  m_ID = id;
+}
+
+bool mitk::ROI::Element::HasTimeStep(TimeStepType t) const
+{
+  return m_Min.count(t) != 0 && m_Max.count(t) != 0;
+}
+
+mitk::Point3D mitk::ROI::Element::GetMin(TimeStepType t) const
+{
+  return m_Min.at(t);
+}
+
+void mitk::ROI::Element::SetMin(const Point3D& min, TimeStepType t)
+{
+  m_Min[t] = min;
+}
+
+mitk::Point3D mitk::ROI::Element::GetMax(TimeStepType t) const
+{
+  return m_Max.at(t);
+}
+
+void mitk::ROI::Element::SetMax(const Point3D& max, TimeStepType t)
+{
+  m_Max[t] = max;
+}
+
+mitk::PropertyList* mitk::ROI::Element::GetDefaultProperties() const
+{
+  return m_DefaultProperties;
+}
+
+void mitk::ROI::Element::SetDefaultProperties(PropertyList* properties)
+{
+  m_DefaultProperties = properties;
+}
+
+mitk::PropertyList* mitk::ROI::Element::GetProperties(TimeStepType t) const
+{
+  if (m_Properties.count(t) != 0)
+    return m_Properties.at(t);
+
+  return nullptr;
+}
+
+void mitk::ROI::Element::SetProperties(PropertyList* properties, TimeStepType t)
+{
+  m_Properties[t] = properties;
+}
+
 mitk::BaseProperty::ConstPointer mitk::ROI::Element::GetConstProperty(const std::string& propertyKey, const std::string& contextName, bool fallBackOnDefaultContext) const
 {
-  return Properties->GetConstProperty(propertyKey, contextName, fallBackOnDefaultContext);
+  if (!contextName.empty())
+  {
+    const TimeStepType t = std::stoul(contextName);
+    auto it = m_Properties.find(t);
+
+    if (it != m_Properties.end() && it->second.IsNotNull())
+    {
+      auto property = it->second->GetConstProperty(propertyKey);
+
+      if (property.IsNotNull())
+        return property;
+    }
+
+    if (!fallBackOnDefaultContext)
+      return nullptr;
+  }
+
+  return m_DefaultProperties->GetConstProperty(propertyKey);
 }
 
 std::vector<std::string> mitk::ROI::Element::GetPropertyKeys(const std::string& contextName, bool includeDefaultContext) const
 {
-  return Properties->GetPropertyKeys(contextName, includeDefaultContext);
+  if (!contextName.empty())
+  {
+    const TimeStepType t = std::stoul(contextName);
+    auto it = m_Properties.find(t);
+
+    std::vector<std::string> result;
+
+    if (it != m_Properties.end() && it->second.IsNotNull())
+      result = it->second->GetPropertyKeys();
+
+    if (includeDefaultContext)
+    {
+      auto keys = m_DefaultProperties->GetPropertyKeys();
+      auto end = result.cend();
+
+      std::remove_copy_if(keys.cbegin(), keys.cend(), std::back_inserter(result), [&, result, end](const std::string& key) {
+        return end != std::find(result.cbegin(), end, key);
+      });
+    }
+
+    return result;
+  }
+
+  return m_DefaultProperties->GetPropertyKeys();
 }
 
 std::vector<std::string> mitk::ROI::Element::GetPropertyContextNames() const
 {
-  return Properties->GetPropertyContextNames();
+  std::vector<std::string> result;
+  result.reserve(m_Properties.size());
+
+  std::transform(m_Properties.cbegin(), m_Properties.cend(), std::back_inserter(result), [](const PropertyListsType::value_type& property) {
+    return std::to_string(property.first);
+  });
+
+  return result;
 }
 
 mitk::BaseProperty* mitk::ROI::Element::GetNonConstProperty(const std::string& propertyKey, const std::string& contextName, bool fallBackOnDefaultContext)
 {
-  return Properties->GetNonConstProperty(propertyKey, contextName, fallBackOnDefaultContext);
+  if (!contextName.empty())
+  {
+    const TimeStepType t = std::stoul(contextName);
+    auto it = m_Properties.find(t);
+
+    if (it != m_Properties.end() && it->second.IsNotNull())
+    {
+      auto* property = it->second->GetNonConstProperty(propertyKey);
+
+      if (property != nullptr)
+        return property;
+    }
+
+    if (!fallBackOnDefaultContext)
+      return nullptr;
+  }
+
+  return m_DefaultProperties->GetNonConstProperty(propertyKey);
 }
 
 void mitk::ROI::Element::SetProperty(const std::string& propertyKey, BaseProperty* property, const std::string& contextName, bool fallBackOnDefaultContext)
 {
-  Properties->SetProperty(propertyKey, property, contextName, fallBackOnDefaultContext);
+  if (!contextName.empty())
+  {
+    const TimeStepType t = std::stoul(contextName);
+    auto it = m_Properties.find(t);
+
+    if (it != m_Properties.end() && it->second.IsNotNull())
+    {
+      it->second->SetProperty(propertyKey, property);
+    }
+    else if (!fallBackOnDefaultContext)
+    {
+      mitkThrow() << "Context \"" << contextName << "\" does not exist!";
+    }
+  }
+
+  m_DefaultProperties->SetProperty(propertyKey, property);
 }
 
 void mitk::ROI::Element::RemoveProperty(const std::string& propertyKey, const std::string& contextName, bool fallBackOnDefaultContext)
 {
-  Properties->RemoveProperty(propertyKey, contextName, fallBackOnDefaultContext);
+  if (!contextName.empty())
+  {
+    const TimeStepType t = std::stoul(contextName);
+    auto it = m_Properties.find(t);
+
+    if (it != m_Properties.end() && it->second.IsNotNull())
+    {
+      it->second->RemoveProperty(propertyKey);
+    }
+    else if (!fallBackOnDefaultContext)
+    {
+      mitkThrow() << "Context \"" << contextName << "\" does not exist!";
+    }
+  }
+
+  m_DefaultProperties->RemoveProperty(propertyKey);
 }
 
 mitk::ROI::ROI()
 {
 }
 
 mitk::ROI::ROI(const Self& other)
   : BaseData(other)
 {
 }
 
 mitk::ROI::~ROI()
 {
 }
 
 size_t mitk::ROI::GetNumberOfElements() const
 {
   return m_Elements.size();
 }
 
-size_t mitk::ROI::AddElement(const Element& element)
+void mitk::ROI::AddElement(const Element& element)
 {
-  m_Elements.push_back(element);
-  return m_Elements.size() - 1;
+  const auto id = element.GetID();
+
+  if (m_Elements.count(id) != 0)
+    mitkThrow() << "ROI already contains an element with ID " << std::to_string(id) << '.';
+
+  m_Elements[id] = element;
 }
 
-const mitk::ROI::Element* mitk::ROI::GetElement(size_t index) const
+const mitk::ROI::Element& mitk::ROI::GetElement(unsigned int id) const
 {
-  return &m_Elements.at(index);
+  return m_Elements.at(id);
 }
 
-mitk::ROI::Element* mitk::ROI::GetElement(size_t index)
+mitk::ROI::Element& mitk::ROI::GetElement(unsigned int id)
 {
-  return &m_Elements.at(index);
+  return m_Elements.at(id);
 }
 
 mitk::ROI::ConstIterator mitk::ROI::begin() const
 {
   return m_Elements.begin();
 }
 
 mitk::ROI::ConstIterator mitk::ROI::end() const
 {
   return m_Elements.end();
 }
 
 mitk::ROI::Iterator mitk::ROI::begin()
 {
   return m_Elements.begin();
 }
 
 mitk::ROI::Iterator mitk::ROI::end()
 {
   return m_Elements.end();
 }
 
 void mitk::ROI::SetRequestedRegionToLargestPossibleRegion()
 {
 }
 
 bool mitk::ROI::RequestedRegionIsOutsideOfTheBufferedRegion()
 {
   return false;
 }
 
 bool mitk::ROI::VerifyRequestedRegion()
 {
   return true;
 }
 
 void mitk::ROI::SetRequestedRegion(const itk::DataObject* data)
 {
 }