diff --git a/Modules/Core/include/mitkItkImageIO.h b/Modules/Core/include/mitkItkImageIO.h
index cefc222130..861243eebc 100644
--- a/Modules/Core/include/mitkItkImageIO.h
+++ b/Modules/Core/include/mitkItkImageIO.h
@@ -1,79 +1,82 @@
 /*============================================================================
 
 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 MITKITKFILEIO_H
 #define MITKITKFILEIO_H
 
 #include "mitkAbstractFileIO.h"
 
 #include <itkImageIOBase.h>
 
 namespace mitk
 {
   /**
    * This class wraps ITK image IO objects as mitk::IFileReader and
    * mitk::IFileWriter objects.
    *
    * Instantiating this class with a given itk::ImageIOBase instance
    * will register corresponding MITK reader/writer services for that
    * ITK ImageIO object.
+   * For all ITK ImageIOs that support the serialization of MetaData
+   * (e.g. nrrd or mhd) the ItkImageIO ensures the serialization
+   * of Identification UID.
    */
   class MITKCORE_EXPORT ItkImageIO : public AbstractFileIO
   {
   public:
     ItkImageIO(itk::ImageIOBase::Pointer imageIO);
     ItkImageIO(const CustomMimeType &mimeType, itk::ImageIOBase::Pointer imageIO, int rank);
 
     // -------------- AbstractFileReader -------------
 
     using AbstractFileReader::Read;
 
     ConfidenceLevel GetReaderConfidenceLevel() const override;
 
     // -------------- AbstractFileWriter -------------
 
     void Write() override;
     ConfidenceLevel GetWriterConfidenceLevel() const override;
 
   protected:
     virtual std::vector<std::string> FixUpImageIOExtensions(const std::string &imageIOName);
     virtual void FixUpCustomMimeTypeName(const std::string &imageIOName, CustomMimeType &customMimeType);
 
     // Fills the m_DefaultMetaDataKeys vector with default values
     virtual void InitializeDefaultMetaDataKeys();
 
     // -------------- AbstractFileReader -------------
     std::vector<itk::SmartPointer<BaseData>> DoRead() override;
 
   private:
     ItkImageIO(const ItkImageIO &other);
 
     ItkImageIO *IOClone() const override;
 
     itk::ImageIOBase::Pointer m_ImageIO;
 
     std::vector<std::string> m_DefaultMetaDataKeys;
   };
 
   /**Helper function that converts the content of a meta data into a time point vector.
    * If MetaData is not valid or cannot be converted an empty vector is returned.*/
   MITKCORE_EXPORT std::vector<TimePointType> ConvertMetaDataObjectToTimePointList(const itk::MetaDataObjectBase* data);
 
 
   /**Helper function that converts the time points of a passed time geometry to a time point list
    and stores it in a itk::MetaDataObject. Use ConvertMetaDataObjectToTimePointList() to convert it back
    to a time point list.*/
   MITKCORE_EXPORT itk::MetaDataObjectBase::Pointer ConvertTimePointListToMetaDataObject(const mitk::TimeGeometry* timeGeometry);
 
 } // namespace mitk
 
 #endif /* MITKITKFILEIO_H */
diff --git a/Modules/Core/src/IO/mitkItkImageIO.cpp b/Modules/Core/src/IO/mitkItkImageIO.cpp
index d4666d22ed..55a4b86dc9 100644
--- a/Modules/Core/src/IO/mitkItkImageIO.cpp
+++ b/Modules/Core/src/IO/mitkItkImageIO.cpp
@@ -1,708 +1,724 @@
 /*============================================================================
 
 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 "mitkItkImageIO.h"
 
 #include <mitkArbitraryTimeGeometry.h>
 #include <mitkCoreServices.h>
 #include <mitkCustomMimeType.h>
 #include <mitkIOMimeTypes.h>
 #include <mitkIPropertyPersistence.h>
 #include <mitkImage.h>
 #include <mitkImageReadAccessor.h>
 #include <mitkLocaleSwitch.h>
+#include <mitkUIDManipulator.h>
 
 #include <itkImage.h>
 #include <itkImageFileReader.h>
 #include <itkImageIOFactory.h>
 #include <itkImageIORegion.h>
 #include <itkMetaDataObject.h>
 
 #include <algorithm>
 
 namespace mitk
 {
   const char *const PROPERTY_NAME_TIMEGEOMETRY_TYPE = "org.mitk.timegeometry.type";
   const char *const PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS = "org.mitk.timegeometry.timepoints";
   const char *const PROPERTY_KEY_TIMEGEOMETRY_TYPE = "org_mitk_timegeometry_type";
   const char *const PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS = "org_mitk_timegeometry_timepoints";
+  const char* const PROPERTY_KEY_UID = "org_mitk_uid";
 
   ItkImageIO::ItkImageIO(const ItkImageIO &other)
     : AbstractFileIO(other), m_ImageIO(dynamic_cast<itk::ImageIOBase *>(other.m_ImageIO->Clone().GetPointer()))
   {
     this->InitializeDefaultMetaDataKeys();
   }
 
   std::vector<std::string> ItkImageIO::FixUpImageIOExtensions(const std::string &imageIOName)
   {
     std::vector<std::string> extensions;
     // Try to fix-up some known ITK image IO classes
     if (imageIOName == "GiplImageIO")
     {
       extensions.push_back("gipl");
       extensions.push_back("gipl.gz");
     }
     else if (imageIOName == "GDCMImageIO")
     {
       extensions.push_back("gdcm");
       extensions.push_back("dcm");
       extensions.push_back("DCM");
       extensions.push_back("dc3");
       extensions.push_back("DC3");
       extensions.push_back("ima");
       extensions.push_back("img");
     }
     else if (imageIOName == "PNGImageIO")
     {
       extensions.push_back("png");
       extensions.push_back("PNG");
     }
     else if (imageIOName == "StimulateImageIO")
     {
       extensions.push_back("spr");
     }
     else if (imageIOName == "HDF5ImageIO")
     {
       extensions.push_back("hdf");
       extensions.push_back("h4");
       extensions.push_back("hdf4");
       extensions.push_back("h5");
       extensions.push_back("hdf5");
       extensions.push_back("he4");
       extensions.push_back("he5");
       extensions.push_back("hd5");
     }
     else if ("GE4ImageIO" == imageIOName || "GE5ImageIO" == imageIOName || "Bruker2dseqImageIO" == imageIOName)
     {
       extensions.push_back("");
     }
 
     if (!extensions.empty())
     {
       MITK_DEBUG << "Fixing up known extensions for " << imageIOName;
     }
 
     return extensions;
   }
 
   void ItkImageIO::FixUpCustomMimeTypeName(const std::string &imageIOName, CustomMimeType &customMimeType)
   {
     if ("GE4ImageIO" == imageIOName)
     {
       customMimeType.SetName(this->AbstractFileReader::GetMimeTypePrefix() + "ge4");
     }
     else if ("GE5ImageIO" == imageIOName)
     {
       customMimeType.SetName(this->AbstractFileReader::GetMimeTypePrefix() + "ge5");
     }
     else if ("Bruker2dseqImageIO" == imageIOName)
     {
       customMimeType.SetName(this->AbstractFileReader::GetMimeTypePrefix() + "bruker2dseq");
     }
   }
 
   ItkImageIO::ItkImageIO(itk::ImageIOBase::Pointer imageIO)
     : AbstractFileIO(Image::GetStaticNameOfClass()), m_ImageIO(imageIO)
   {
     if (m_ImageIO.IsNull())
     {
       mitkThrow() << "ITK ImageIOBase argument must not be nullptr";
     }
 
     this->AbstractFileReader::SetMimeTypePrefix(IOMimeTypes::DEFAULT_BASE_NAME() + ".image.");
     this->InitializeDefaultMetaDataKeys();
 
     std::vector<std::string> readExtensions = m_ImageIO->GetSupportedReadExtensions();
 
     if (readExtensions.empty())
     {
       std::string imageIOName = m_ImageIO->GetNameOfClass();
       MITK_DEBUG << "ITK ImageIOBase " << imageIOName << " does not provide read extensions";
       readExtensions = FixUpImageIOExtensions(imageIOName);
     }
 
     CustomMimeType customReaderMimeType;
     customReaderMimeType.SetCategory("Images");
     for (std::vector<std::string>::const_iterator iter = readExtensions.begin(), endIter = readExtensions.end();
          iter != endIter;
          ++iter)
     {
       std::string extension = *iter;
       if (!extension.empty() && extension[0] == '.')
       {
         extension.assign(iter->begin() + 1, iter->end());
       }
       customReaderMimeType.AddExtension(extension);
     }
 
     auto extensions = customReaderMimeType.GetExtensions();
     if (extensions.empty() || (extensions.size() == 1 && extensions[0].empty()))
     {
       std::string imageIOName = m_ImageIO->GetNameOfClass();
       FixUpCustomMimeTypeName(imageIOName, customReaderMimeType);
     }
 
     this->AbstractFileReader::SetMimeType(customReaderMimeType);
 
     std::vector<std::string> writeExtensions = imageIO->GetSupportedWriteExtensions();
     if (writeExtensions.empty())
     {
       std::string imageIOName = imageIO->GetNameOfClass();
       MITK_DEBUG << "ITK ImageIOBase " << imageIOName << " does not provide write extensions";
       writeExtensions = FixUpImageIOExtensions(imageIOName);
     }
 
     if (writeExtensions != readExtensions)
     {
       CustomMimeType customWriterMimeType;
       customWriterMimeType.SetCategory("Images");
       for (std::vector<std::string>::const_iterator iter = writeExtensions.begin(), endIter = writeExtensions.end();
            iter != endIter;
            ++iter)
       {
         std::string extension = *iter;
         if (!extension.empty() && extension[0] == '.')
         {
           extension.assign(iter->begin() + 1, iter->end());
         }
         customWriterMimeType.AddExtension(extension);
       }
 
       auto extensions = customWriterMimeType.GetExtensions();
       if (extensions.empty() || (extensions.size() == 1 && extensions[0].empty()))
       {
         std::string imageIOName = m_ImageIO->GetNameOfClass();
         FixUpCustomMimeTypeName(imageIOName, customWriterMimeType);
       }
 
       this->AbstractFileWriter::SetMimeType(customWriterMimeType);
     }
 
     std::string description = std::string("ITK ") + imageIO->GetNameOfClass();
     this->SetReaderDescription(description);
     this->SetWriterDescription(description);
 
     this->RegisterService();
   }
 
   ItkImageIO::ItkImageIO(const CustomMimeType &mimeType, itk::ImageIOBase::Pointer imageIO, int rank)
     : AbstractFileIO(Image::GetStaticNameOfClass(), mimeType, std::string("ITK ") + imageIO->GetNameOfClass()),
       m_ImageIO(imageIO)
   {
     if (m_ImageIO.IsNull())
     {
       mitkThrow() << "ITK ImageIOBase argument must not be nullptr";
     }
 
     this->AbstractFileReader::SetMimeTypePrefix(IOMimeTypes::DEFAULT_BASE_NAME() + ".image.");
     this->InitializeDefaultMetaDataKeys();
 
     if (rank)
     {
       this->AbstractFileReader::SetRanking(rank);
       this->AbstractFileWriter::SetRanking(rank);
     }
 
     this->RegisterService();
   }
 
   std::vector<TimePointType> ConvertMetaDataObjectToTimePointList(const itk::MetaDataObjectBase* data)
   {
     const auto* timeGeometryTimeData =
       dynamic_cast<const itk::MetaDataObject<std::string>*>(data);
     std::vector<TimePointType> result;
 
     if (timeGeometryTimeData)
     {
       std::string dataStr = timeGeometryTimeData->GetMetaDataObjectValue();
       std::stringstream stream(dataStr);
       TimePointType tp;
       while (stream >> tp)
       {
         result.push_back(tp);
       }
     }
 
     return result;
   };
 
   itk::MetaDataObjectBase::Pointer ConvertTimePointListToMetaDataObject(const mitk::TimeGeometry* timeGeometry)
   {
     std::stringstream stream;
     stream << timeGeometry->GetTimeBounds(0)[0];
     const auto maxTimePoints = timeGeometry->CountTimeSteps();
     for (TimeStepType pos = 0; pos < maxTimePoints; ++pos)
     {
       stream << " " << timeGeometry->GetTimeBounds(pos)[1];
     }
     auto result = itk::MetaDataObject<std::string>::New();
     result->SetMetaDataObjectValue(stream.str());
     return result.GetPointer();
   };
 
   std::vector<BaseData::Pointer> ItkImageIO::DoRead()
   {
     std::vector<BaseData::Pointer> result;
     mitk::LocaleSwitch localeSwitch("C");
 
     Image::Pointer image = Image::New();
 
     const unsigned int MINDIM = 2;
     const unsigned int MAXDIM = 4;
 
     const std::string path = this->GetLocalFileName();
 
     MITK_INFO << "loading " << path << " via itk::ImageIOFactory... " << std::endl;
 
     // Check to see if we can read the file given the name or prefix
     if (path.empty())
     {
       mitkThrow() << "Empty filename in mitk::ItkImageIO ";
     }
 
     // Got to allocate space for the image. Determine the characteristics of
     // the image.
     m_ImageIO->SetFileName(path);
     m_ImageIO->ReadImageInformation();
 
     unsigned int ndim = m_ImageIO->GetNumberOfDimensions();
     if (ndim < MINDIM || ndim > MAXDIM)
     {
       MITK_WARN << "Sorry, only dimensions 2, 3 and 4 are supported. The given file has " << ndim
                 << " dimensions! Reading as 4D.";
       ndim = MAXDIM;
     }
 
     itk::ImageIORegion ioRegion(ndim);
     itk::ImageIORegion::SizeType ioSize = ioRegion.GetSize();
     itk::ImageIORegion::IndexType ioStart = ioRegion.GetIndex();
 
     unsigned int dimensions[MAXDIM];
     dimensions[0] = 0;
     dimensions[1] = 0;
     dimensions[2] = 0;
     dimensions[3] = 0;
 
     ScalarType spacing[MAXDIM];
     spacing[0] = 1.0f;
     spacing[1] = 1.0f;
     spacing[2] = 1.0f;
     spacing[3] = 1.0f;
 
     Point3D origin;
     origin.Fill(0);
 
     unsigned int i;
     for (i = 0; i < ndim; ++i)
     {
       ioStart[i] = 0;
       ioSize[i] = m_ImageIO->GetDimensions(i);
       if (i < MAXDIM)
       {
         dimensions[i] = m_ImageIO->GetDimensions(i);
         spacing[i] = m_ImageIO->GetSpacing(i);
         if (spacing[i] <= 0)
           spacing[i] = 1.0f;
       }
       if (i < 3)
       {
         origin[i] = m_ImageIO->GetOrigin(i);
       }
     }
 
     ioRegion.SetSize(ioSize);
     ioRegion.SetIndex(ioStart);
 
     MITK_INFO << "ioRegion: " << ioRegion << std::endl;
     m_ImageIO->SetIORegion(ioRegion);
     void *buffer = new unsigned char[m_ImageIO->GetImageSizeInBytes()];
     m_ImageIO->Read(buffer);
 
     image->Initialize(MakePixelType(m_ImageIO), ndim, dimensions);
     image->SetImportChannel(buffer, 0, Image::ManageMemory);
 
     const itk::MetaDataDictionary &dictionary = m_ImageIO->GetMetaDataDictionary();
 
     // access direction of itk::Image and include spacing
     mitk::Matrix3D matrix;
     matrix.SetIdentity();
     unsigned int j, itkDimMax3 = (ndim >= 3 ? 3 : ndim);
     for (i = 0; i < itkDimMax3; ++i)
       for (j = 0; j < itkDimMax3; ++j)
         matrix[i][j] = m_ImageIO->GetDirection(j)[i];
 
     // re-initialize PlaneGeometry with origin and direction
     PlaneGeometry *planeGeometry = image->GetSlicedGeometry(0)->GetPlaneGeometry(0);
     planeGeometry->SetOrigin(origin);
     planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix);
 
     // re-initialize SlicedGeometry3D
     SlicedGeometry3D *slicedGeometry = image->GetSlicedGeometry(0);
     slicedGeometry->InitializeEvenlySpaced(planeGeometry, image->GetDimension(2));
     slicedGeometry->SetSpacing(spacing);
 
     MITK_INFO << slicedGeometry->GetCornerPoint(false, false, false);
     MITK_INFO << slicedGeometry->GetCornerPoint(true, true, true);
 
     // re-initialize TimeGeometry
     TimeGeometry::Pointer timeGeometry;
 
     if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE) || dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TYPE))
     { // also check for the name because of backwards compatibility. Past code version stored with the name and not with
       // the key
       itk::MetaDataObject<std::string>::ConstPointer timeGeometryTypeData = nullptr;
       if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE))
       {
         timeGeometryTypeData =
           dynamic_cast<const itk::MetaDataObject<std::string> *>(dictionary.Get(PROPERTY_NAME_TIMEGEOMETRY_TYPE));
       }
       else
       {
         timeGeometryTypeData =
           dynamic_cast<const itk::MetaDataObject<std::string> *>(dictionary.Get(PROPERTY_KEY_TIMEGEOMETRY_TYPE));
       }
 
       if (timeGeometryTypeData->GetMetaDataObjectValue() == ArbitraryTimeGeometry::GetStaticNameOfClass())
       {
         MITK_INFO << "used time geometry: " << ArbitraryTimeGeometry::GetStaticNameOfClass();
         typedef std::vector<TimePointType> TimePointVector;
         TimePointVector timePoints;
 
         if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS))
         {
           timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS));
         }
         else if (dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS))
         {
           timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS));
         }
 
         if (timePoints.empty())
         {
           MITK_ERROR << "Stored timepoints are empty. Meta information seems to bee invalid. Switch to ProportionalTimeGeometry fallback";
         }
         else if (timePoints.size() - 1 != image->GetDimension(3))
         {
           MITK_ERROR << "Stored timepoints (" << timePoints.size() - 1 << ") and size of image time dimension ("
                      << image->GetDimension(3) << ") do not match. Switch to ProportionalTimeGeometry fallback";
         }
         else
         {
           ArbitraryTimeGeometry::Pointer arbitraryTimeGeometry = ArbitraryTimeGeometry::New();
           TimePointVector::const_iterator pos = timePoints.begin();
           auto prePos = pos++;
 
           for (; pos != timePoints.end(); ++prePos, ++pos)
           {
             arbitraryTimeGeometry->AppendNewTimeStepClone(slicedGeometry, *prePos, *pos);
           }
 
           timeGeometry = arbitraryTimeGeometry;
         }
       }
     }
 
     if (timeGeometry.IsNull())
     { // Fallback. If no other valid time geometry has been created, create a ProportionalTimeGeometry
       MITK_INFO << "used time geometry: " << ProportionalTimeGeometry::GetStaticNameOfClass();
       ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New();
       propTimeGeometry->Initialize(slicedGeometry, image->GetDimension(3));
       timeGeometry = propTimeGeometry;
     }
 
     image->SetTimeGeometry(timeGeometry);
 
     buffer = nullptr;
     MITK_INFO << "number of image components: " << image->GetPixelType().GetNumberOfComponents();
 
     for (auto iter = dictionary.Begin(), iterEnd = dictionary.End(); iter != iterEnd;
          ++iter)
     {
       if (iter->second->GetMetaDataObjectTypeInfo() == typeid(std::string))
       {
         const std::string &key = iter->first;
         std::string assumedPropertyName = key;
         std::replace(assumedPropertyName.begin(), assumedPropertyName.end(), '_', '.');
 
         std::string mimeTypeName = GetMimeType()->GetName();
 
         // Check if there is already a info for the key and our mime type.
         mitk::CoreServicePointer<IPropertyPersistence> propPersistenceService(mitk::CoreServices::GetPropertyPersistence());
         IPropertyPersistence::InfoResultType infoList = propPersistenceService->GetInfoByKey(key);
 
         auto predicate = [&mimeTypeName](const PropertyPersistenceInfo::ConstPointer &x) {
           return x.IsNotNull() && x->GetMimeTypeName() == mimeTypeName;
         };
         auto finding = std::find_if(infoList.begin(), infoList.end(), predicate);
 
         if (finding == infoList.end())
         {
           auto predicateWild = [](const PropertyPersistenceInfo::ConstPointer &x) {
             return x.IsNotNull() && x->GetMimeTypeName() == PropertyPersistenceInfo::ANY_MIMETYPE_NAME();
           };
           finding = std::find_if(infoList.begin(), infoList.end(), predicateWild);
         }
 
         PropertyPersistenceInfo::ConstPointer info;
 
         if (finding != infoList.end())
         {
           assumedPropertyName = (*finding)->GetName();
           info = *finding;
         }
         else
         { // we have not found anything suitable so we generate our own info
           auto newInfo = PropertyPersistenceInfo::New();
           newInfo->SetNameAndKey(assumedPropertyName, key);
           newInfo->SetMimeTypeName(PropertyPersistenceInfo::ANY_MIMETYPE_NAME());
           info = newInfo;
         }
 
         std::string value =
           dynamic_cast<itk::MetaDataObject<std::string> *>(iter->second.GetPointer())->GetMetaDataObjectValue();
 
         mitk::BaseProperty::Pointer loadedProp = info->GetDeserializationFunction()(value);
 
         image->SetProperty(assumedPropertyName.c_str(), loadedProp);
 
         // Read properties should be persisted unless they are default properties
         // which are written anyway
         bool isDefaultKey(false);
 
         for (const auto &defaultKey : m_DefaultMetaDataKeys)
         {
           if (defaultKey.length() <= assumedPropertyName.length())
           {
             // does the start match the default key
             if (assumedPropertyName.substr(0, defaultKey.length()).find(defaultKey) != std::string::npos)
             {
               isDefaultKey = true;
               break;
             }
           }
         }
 
         if (!isDefaultKey)
         {
           propPersistenceService->AddInfo(info);
         }
       }
     }
 
+    // Handle UID
+    if (dictionary.HasKey(PROPERTY_KEY_UID))
+    {
+      itk::MetaDataObject<std::string>::ConstPointer uidData = dynamic_cast<const itk::MetaDataObject<std::string>*>(dictionary.Get(PROPERTY_KEY_UID));
+      if (uidData.IsNotNull())
+      {
+        mitk::UIDManipulator uidManipulator(image);
+        uidManipulator.SetUID(uidData->GetMetaDataObjectValue());
+      }
+    }
+
     MITK_INFO << "...finished!";
 
     result.push_back(image.GetPointer());
     return result;
   }
 
   AbstractFileIO::ConfidenceLevel ItkImageIO::GetReaderConfidenceLevel() const
   {
     return m_ImageIO->CanReadFile(GetLocalFileName().c_str()) ? IFileReader::Supported : IFileReader::Unsupported;
   }
 
   void ItkImageIO::Write()
   {
     const auto *image = dynamic_cast<const mitk::Image *>(this->GetInput());
 
     if (image == nullptr)
     {
       mitkThrow() << "Cannot write non-image data";
     }
 
     // Switch the current locale to "C"
     LocaleSwitch localeSwitch("C");
 
     // Clone the image geometry, because we might have to change it
     // for writing purposes
     BaseGeometry::Pointer geometry = image->GetGeometry()->Clone();
 
     // Check if geometry information will be lost
     if (image->GetDimension() == 2 && !geometry->Is2DConvertable())
     {
       MITK_WARN << "Saving a 2D image with 3D geometry information. Geometry information will be lost! You might "
                    "consider using Convert2Dto3DImageFilter before saving.";
 
       // set matrix to identity
       mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New();
       affTrans->SetIdentity();
       mitk::Vector3D spacing = geometry->GetSpacing();
       mitk::Point3D origin = geometry->GetOrigin();
       geometry->SetIndexToWorldTransform(affTrans);
       geometry->SetSpacing(spacing);
       geometry->SetOrigin(origin);
     }
 
     LocalFile localFile(this);
     const std::string path = localFile.GetFileName();
 
     MITK_INFO << "Writing image: " << path << std::endl;
 
     try
     {
       // Implementation of writer using itkImageIO directly. This skips the use
       // of templated itkImageFileWriter, which saves the multiplexing on MITK side.
 
       const unsigned int dimension = image->GetDimension();
       const unsigned int *const dimensions = image->GetDimensions();
       const mitk::PixelType pixelType = image->GetPixelType();
       const mitk::Vector3D mitkSpacing = geometry->GetSpacing();
       const mitk::Point3D mitkOrigin = geometry->GetOrigin();
 
       // Due to templating in itk, we are forced to save a 4D spacing and 4D Origin,
       // though they are not supported in MITK
       itk::Vector<double, 4u> spacing4D;
       spacing4D[0] = mitkSpacing[0];
       spacing4D[1] = mitkSpacing[1];
       spacing4D[2] = mitkSpacing[2];
       spacing4D[3] = 1; // There is no support for a 4D spacing. However, we should have a valid value here
 
       itk::Vector<double, 4u> origin4D;
       origin4D[0] = mitkOrigin[0];
       origin4D[1] = mitkOrigin[1];
       origin4D[2] = mitkOrigin[2];
       origin4D[3] = 0; // There is no support for a 4D origin. However, we should have a valid value here
 
       // Set the necessary information for imageIO
       m_ImageIO->SetNumberOfDimensions(dimension);
       m_ImageIO->SetPixelType(pixelType.GetPixelType());
       m_ImageIO->SetComponentType(pixelType.GetComponentType() < PixelComponentUserType ?
                                     static_cast<itk::ImageIOBase::IOComponentType>(pixelType.GetComponentType()) :
                                     itk::ImageIOBase::UNKNOWNCOMPONENTTYPE);
       m_ImageIO->SetNumberOfComponents(pixelType.GetNumberOfComponents());
 
       itk::ImageIORegion ioRegion(dimension);
 
       for (unsigned int i = 0; i < dimension; i++)
       {
         m_ImageIO->SetDimensions(i, dimensions[i]);
         m_ImageIO->SetSpacing(i, spacing4D[i]);
         m_ImageIO->SetOrigin(i, origin4D[i]);
 
         mitk::Vector3D mitkDirection;
         mitkDirection.SetVnlVector(geometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i));
         itk::Vector<double, 4u> direction4D;
         direction4D[0] = mitkDirection[0];
         direction4D[1] = mitkDirection[1];
         direction4D[2] = mitkDirection[2];
 
         // MITK only supports a 3x3 direction matrix. Due to templating in itk, however, we must
         // save a 4x4 matrix for 4D images. in this case, add an homogneous component to the matrix.
         if (i == 3)
         {
           direction4D[3] = 1; // homogenous component
         }
         else
         {
           direction4D[3] = 0;
         }
         vnl_vector<double> axisDirection(dimension);
         for (unsigned int j = 0; j < dimension; j++)
         {
           axisDirection[j] = direction4D[j] / spacing4D[i];
         }
         m_ImageIO->SetDirection(i, axisDirection);
 
         ioRegion.SetSize(i, image->GetLargestPossibleRegion().GetSize(i));
         ioRegion.SetIndex(i, image->GetLargestPossibleRegion().GetIndex(i));
       }
 
       // use compression if available
       m_ImageIO->UseCompressionOn();
 
       m_ImageIO->SetIORegion(ioRegion);
       m_ImageIO->SetFileName(path);
 
       // Handle time geometry
       const auto *arbitraryTG = dynamic_cast<const ArbitraryTimeGeometry *>(image->GetTimeGeometry());
       if (arbitraryTG)
       {
         itk::EncapsulateMetaData<std::string>(m_ImageIO->GetMetaDataDictionary(),
                                               PROPERTY_KEY_TIMEGEOMETRY_TYPE,
                                               ArbitraryTimeGeometry::GetStaticNameOfClass());
 
         auto metaTimePoints = ConvertTimePointListToMetaDataObject(arbitraryTG);
         m_ImageIO->GetMetaDataDictionary().Set(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS, metaTimePoints);
       }
 
       // Handle properties
       mitk::PropertyList::Pointer imagePropertyList = image->GetPropertyList();
 
       for (const auto &property : *imagePropertyList->GetMap())
       {
         mitk::CoreServicePointer<IPropertyPersistence> propPersistenceService(mitk::CoreServices::GetPropertyPersistence());
         IPropertyPersistence::InfoResultType infoList = propPersistenceService->GetInfo(property.first, GetMimeType()->GetName(), true);
 
         if (infoList.empty())
         {
           continue;
         }
 
         std::string value = infoList.front()->GetSerializationFunction()(property.second);
 
         if (value == mitk::BaseProperty::VALUE_CANNOT_BE_CONVERTED_TO_STRING)
         {
           continue;
         }
 
         std::string key = infoList.front()->GetKey();
 
         itk::EncapsulateMetaData<std::string>(m_ImageIO->GetMetaDataDictionary(), key, value);
       }
 
+      // Handle UID
+      itk::EncapsulateMetaData<std::string>(m_ImageIO->GetMetaDataDictionary(), PROPERTY_KEY_UID, image->GetUID());
+
       ImageReadAccessor imageAccess(image);
       LocaleSwitch localeSwitch2("C");
       m_ImageIO->Write(imageAccess.GetData());
     }
     catch (const std::exception &e)
     {
       mitkThrow() << e.what();
     }
   }
 
   AbstractFileIO::ConfidenceLevel ItkImageIO::GetWriterConfidenceLevel() const
   {
     // Check if the image dimension is supported
     const auto *image = dynamic_cast<const Image *>(this->GetInput());
     if (image == nullptr)
     {
       // We cannot write a null object, DUH!
       return IFileWriter::Unsupported;
     }
 
     if (!m_ImageIO->SupportsDimension(image->GetDimension()))
     {
       // okay, dimension is not supported. We have to look at a special case:
       // 3D-Image with one slice. We can treat that as a 2D image.
       if ((image->GetDimension() == 3) && (image->GetSlicedGeometry()->GetSlices() == 1))
         return IFileWriter::Supported;
       else
         return IFileWriter::Unsupported;
     }
 
     // Check if geometry information will be lost
     if (image->GetDimension() == 2 && !image->GetGeometry()->Is2DConvertable())
     {
       return IFileWriter::PartiallySupported;
     }
     return IFileWriter::Supported;
   }
 
   ItkImageIO *ItkImageIO::IOClone() const { return new ItkImageIO(*this); }
   void ItkImageIO::InitializeDefaultMetaDataKeys()
   {
     this->m_DefaultMetaDataKeys.push_back("NRRD.space");
     this->m_DefaultMetaDataKeys.push_back("NRRD.kinds");
     this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TYPE);
     this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS);
     this->m_DefaultMetaDataKeys.push_back("ITK.InputFilterName");
   }
 }
diff --git a/Modules/Core/test/mitkItkImageIOTest.cpp b/Modules/Core/test/mitkItkImageIOTest.cpp
index 1c27efa749..1f608cc5f2 100644
--- a/Modules/Core/test/mitkItkImageIOTest.cpp
+++ b/Modules/Core/test/mitkItkImageIOTest.cpp
@@ -1,423 +1,427 @@
 /*============================================================================
 
 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 "mitkException.h"
 #include <mitkStandardFileLocations.h>
 #include <mitkTestFixture.h>
 #include <mitkTestingMacros.h>
 
 #include "mitkIOUtil.h"
 #include "mitkITKImageImport.h"
 #include <mitkExtractSliceFilter.h>
 
 #include "itksys/SystemTools.hxx"
 #include <itkImageRegionIterator.h>
 
 #include <fstream>
 #include <iostream>
 
 #ifdef WIN32
 #include "process.h"
 #else
 #include <unistd.h>
 #endif
 
 class mitkItkImageIOTestSuite : public mitk::TestFixture
 {
   CPPUNIT_TEST_SUITE(mitkItkImageIOTestSuite);
   MITK_TEST(TestImageWriterJpg);
   MITK_TEST(TestImageWriterPng1);
   MITK_TEST(TestImageWriterPng2);
   MITK_TEST(TestImageWriterPng3);
   MITK_TEST(TestImageWriterSimple);
   MITK_TEST(TestWrite3DImageWithOnePlane);
   MITK_TEST(TestWrite3DImageWithTwoPlanes);
   MITK_TEST(TestWrite3DplusT_ArbitraryTG);
   MITK_TEST(TestWrite3DplusT_ProportionalTG);
   CPPUNIT_TEST_SUITE_END();
 
 public:
   void setUp() override {}
   void tearDown() override {}
   void TestImageWriterJpg() { TestImageWriter("NrrdWritingTestImage.jpg"); }
   void TestImageWriterPng1() { TestImageWriter("Png2D-bw.png"); }
   void TestImageWriterPng2() { TestImageWriter("RenderingTestData/rgbImage.png"); }
   void TestImageWriterPng3() { TestImageWriter("RenderingTestData/rgbaImage.png"); }
   void TestWrite3DplusT_ArbitraryTG()
   {
     TestImageWriter("3D+t-ITKIO-TestData/LinearModel_4D_arbitrary_time_geometry.nrrd");
   }
 
   void TestWrite3DplusT_ProportionalTG()
   {
     TestImageWriter("3D+t-ITKIO-TestData/LinearModel_4D_prop_time_geometry.nrrd");
   }
 
   void TestImageWriterSimple()
   {
     // TODO
   }
 
   std::string AppendExtension(const std::string &filename, const char *extension)
   {
     std::string new_filename = filename;
 
     new_filename += extension;
     return new_filename;
   }
 
   bool CompareImageMetaData(mitk::Image::Pointer image, mitk::Image::Pointer reference, bool checkPixelType = true)
   {
     // switch to AreIdentical() methods as soon as Bug 11925 (Basic comparison operators) is fixed
 
     if (image->GetDimension() != reference->GetDimension())
     {
       MITK_ERROR << "The image dimension differs: IN (" << image->GetDimension() << ") REF("
                  << reference->GetDimension() << ")";
       return false;
     }
 
     // pixel type
     if (checkPixelType &&
         (image->GetPixelType() != reference->GetPixelType() &&
          image->GetPixelType().GetBitsPerComponent() != reference->GetPixelType().GetBitsPerComponent()))
     {
       MITK_ERROR << "Pixeltype differs ( image=" << image->GetPixelType().GetPixelTypeAsString() << "["
                  << image->GetPixelType().GetBitsPerComponent() << "]"
                  << " reference=" << reference->GetPixelType().GetPixelTypeAsString() << "["
                  << reference->GetPixelType().GetBitsPerComponent() << "]"
                  << " )";
       return false;
     }
 
     return true;
   }
 
   /*
   Test writing picture formats like *.bmp, *.png, *.tiff or *.jpg
   NOTE: Saving as picture format must ignore PixelType comparison - not all bits per components are supported (see
   specification of the format)
   */
   void TestPictureWriting(mitk::Image *image, const std::string &filename, const std::string &extension)
   {
     const std::string fullFileName = AppendExtension(filename, extension.c_str());
 
     mitk::Image::Pointer singleSliceImage = nullptr;
     if (image->GetDimension() == 3)
     {
       mitk::ExtractSliceFilter::Pointer extractFilter = mitk::ExtractSliceFilter::New();
       extractFilter->SetInput(image);
       extractFilter->SetWorldGeometry(image->GetSlicedGeometry()->GetPlaneGeometry(0));
 
       extractFilter->Update();
       singleSliceImage = extractFilter->GetOutput();
 
       // test 3D writing in format supporting only 2D
       mitk::IOUtil::Save(image, fullFileName);
 
       // test images
       unsigned int foundImagesCount = 0;
 
       // if the image only contains one sinlge slice the itkImageSeriesWriter won't add a number like
       // filename.XX.extension
       if (image->GetDimension(2) == 1)
       {
         std::stringstream series_filenames;
         series_filenames << filename << extension;
         mitk::Image::Pointer compareImage = mitk::IOUtil::Load<mitk::Image>(series_filenames.str());
         if (compareImage.IsNotNull())
         {
           foundImagesCount++;
           MITK_TEST_CONDITION(
             CompareImageMetaData(singleSliceImage, compareImage, false),
             "Image meta data unchanged after writing and loading again. "); // ignore bits per component
         }
         remove(series_filenames.str().c_str());
       }
       else // test the whole slice stack
       {
         for (unsigned int i = 0; i < image->GetDimension(2); i++)
         {
           std::stringstream series_filenames;
           series_filenames << filename << "." << i + 1 << extension;
           mitk::Image::Pointer compareImage = mitk::IOUtil::Load<mitk::Image>(series_filenames.str());
           if (compareImage.IsNotNull())
           {
             foundImagesCount++;
             MITK_TEST_CONDITION(
               CompareImageMetaData(singleSliceImage, compareImage, false),
               "Image meta data unchanged after writing and loading again. "); // ignore bits per component
           }
           remove(series_filenames.str().c_str());
         }
       }
       MITK_TEST_CONDITION(foundImagesCount == image->GetDimension(2),
                           "All 2D-Slices of a 3D image were stored correctly.");
     }
     else if (image->GetDimension() == 2)
     {
       singleSliceImage = image;
     }
 
     // test 2D writing
     if (singleSliceImage.IsNotNull())
     {
       try
       {
         mitk::IOUtil::Save(singleSliceImage, fullFileName);
 
         mitk::Image::Pointer compareImage = mitk::IOUtil::Load<mitk::Image>(fullFileName.c_str());
         MITK_TEST_CONDITION_REQUIRED(compareImage.IsNotNull(), "Image stored was succesfully loaded again");
 
         MITK_TEST_CONDITION_REQUIRED(
           CompareImageMetaData(singleSliceImage, compareImage, false),
           "Image meta data unchanged after writing and loading again. "); // ignore bits per component
         remove(fullFileName.c_str());
       }
       catch (itk::ExceptionObject &e)
       {
         MITK_TEST_FAILED_MSG(<< "Exception during file writing for ." << extension << ": " << e.what());
       }
     }
   }
 
   /**
   *  test for writing NRRDs
   */
   void TestNRRDWriting(const mitk::Image *image)
   {
     CPPUNIT_ASSERT_MESSAGE("Internal error. Passed reference image is null.", image);
 
     std::ofstream tmpStream;
     std::string tmpFilePath = mitk::IOUtil::CreateTemporaryFile(tmpStream, "XXXXXX.nrrd");
     tmpStream.close();
 
     try
     {
       mitk::IOUtil::Save(image, tmpFilePath);
 
       mitk::Image::Pointer compareImage = mitk::IOUtil::Load<mitk::Image>(tmpFilePath);
       CPPUNIT_ASSERT_MESSAGE("Image stored in NRRD format was succesfully loaded again", compareImage.IsNotNull());
 
       /*It would make sence to check the images as well (see commented cppunit assert),
         but currently there seems to be a problem (exception) with most of the test images
         (partly it seems to be a problem when try to access the pixel content by AccessByItk_1
         in mitk::CompareImageDataFilter.
         This problem should be dealt with in Bug 19533 - mitkITKImageIOTest needs improvement */
       // CPPUNIT_ASSERT_MESSAGE("Images are equal.", mitk::Equal(*image, *compareImage, mitk::eps, true));
       CPPUNIT_ASSERT_MESSAGE(
         "TimeGeometries are equal.",
         mitk::Equal(*(image->GetTimeGeometry()), *(compareImage->GetTimeGeometry()), mitk::eps, true));
 
+      CPPUNIT_ASSERT_EQUAL_MESSAGE("Error, read image has different UID", image->GetUID(), compareImage->GetUID());
+
       remove(tmpFilePath.c_str());
     }
     catch (...)
     {
       std::remove(tmpFilePath.c_str());
       CPPUNIT_FAIL("Exception during NRRD file writing");
     }
   }
 
   /**
   *  test for writing MHDs
   */
   void TestMHDWriting(const mitk::Image *image)
   {
     CPPUNIT_ASSERT_MESSAGE("Internal error. Passed reference image is null.", image);
 
     std::ofstream tmpStream;
     std::string tmpFilePath = mitk::IOUtil::CreateTemporaryFile(tmpStream, "XXXXXX.mhd");
     tmpStream.close();
 
     std::string tmpFilePathWithoutExt = tmpFilePath.substr(0, tmpFilePath.size() - 4);
 
     try
     {
       mitk::IOUtil::Save(image, tmpFilePath);
 
       mitk::Image::Pointer compareImage = mitk::IOUtil::Load<mitk::Image>(tmpFilePath);
       CPPUNIT_ASSERT_MESSAGE("Image stored in MHD format was succesfully loaded again! ", compareImage.IsNotNull());
 
       CPPUNIT_ASSERT_MESSAGE(".mhd file exists",
                              itksys::SystemTools::FileExists((tmpFilePathWithoutExt + ".mhd").c_str()));
       CPPUNIT_ASSERT_MESSAGE(".raw or .zraw exists",
                              itksys::SystemTools::FileExists((tmpFilePathWithoutExt + ".raw").c_str()) ||
                                itksys::SystemTools::FileExists((tmpFilePathWithoutExt + ".zraw").c_str()));
 
       /*It would make sence to check the images as well (see commented cppunit assert),
       but currently there seems to be a problem (exception) with most of the test images
       (partly it seems to be a problem when try to access the pixel content by AccessByItk_1
       in mitk::CompareImageDataFilter.
       This problem should be dealt with in Bug 19533 - mitkITKImageIOTest needs improvement */
       // CPPUNIT_ASSERT_MESSAGE("Images are equal.", mitk::Equal(*image, *compareImage, mitk::eps, true));
       CPPUNIT_ASSERT_MESSAGE("TimeGeometries are equal.",
                              mitk::Equal(*(image->GetTimeGeometry()), *(compareImage->GetTimeGeometry()), 5e-4, true));
 
+      CPPUNIT_ASSERT_EQUAL_MESSAGE("Error, read image has different UID", image->GetUID(), compareImage->GetUID());
+
       // delete
       remove(tmpFilePath.c_str());
       remove((tmpFilePathWithoutExt + ".raw").c_str());
       remove((tmpFilePathWithoutExt + ".zraw").c_str());
     }
     catch (...)
     {
       CPPUNIT_FAIL("Exception during.mhd file writing");
     }
   }
 
   /**
   *  test for "ImageWriter".
   *
   *  argc and argv are the command line parameters which were passed to
   *  the ADD_TEST command in the CMakeLists.txt file. For the automatic
   *  tests, argv is either empty for the simple tests or contains the filename
   *  of a test image for the image tests (see CMakeLists.txt).
   */
   void TestImageWriter(std::string sourcefile)
   {
     sourcefile = GetTestDataFilePath(sourcefile);
 
     // load image
     CPPUNIT_ASSERT_MESSAGE("Checking whether source image exists", itksys::SystemTools::FileExists(sourcefile.c_str()));
 
     mitk::Image::Pointer image = nullptr;
 
     try
     {
       image = mitk::IOUtil::Load<mitk::Image>(sourcefile);
     }
     catch (...)
     {
       CPPUNIT_FAIL("Exception during file loading:");
     }
 
     CPPUNIT_ASSERT_MESSAGE("loaded image not nullptr", image.IsNotNull());
 
     // write ITK .mhd image (2D and 3D only)
     if (image->GetDimension() <= 3)
     {
       TestMHDWriting(image);
     }
 
     // testing more component image writing as nrrd files
     TestNRRDWriting(image);
 
     std::ofstream tmpStream;
     std::string tmpFilePath = mitk::IOUtil::CreateTemporaryFile(tmpStream, "XXXXXX");
     tmpStream.close();
 
     TestPictureWriting(image, tmpFilePath, ".png");
     TestPictureWriting(image, tmpFilePath, ".jpg");
     TestPictureWriting(image, tmpFilePath, ".tiff");
     TestPictureWriting(image, tmpFilePath, ".bmp");
     // always end with this!
   }
 
   /**
   * Try to write a 3D image with only one plane (a 2D images in disguise for all intents and purposes)
   */
   void TestWrite3DImageWithOnePlane()
   {
     typedef itk::Image<unsigned char, 3> ImageType;
 
     ImageType::Pointer itkImage = ImageType::New();
 
     ImageType::IndexType start;
     start.Fill(0);
 
     ImageType::SizeType size;
     size[0] = 100;
     size[1] = 100;
     size[2] = 1;
 
     ImageType::RegionType region;
     region.SetSize(size);
     region.SetIndex(start);
     itkImage->SetRegions(region);
     itkImage->Allocate();
     itkImage->FillBuffer(0);
 
     itk::ImageRegionIterator<ImageType> imageIterator(itkImage, itkImage->GetLargestPossibleRegion());
 
     // Make two squares
     while (!imageIterator.IsAtEnd())
     {
       if ((imageIterator.GetIndex()[0] > 5 && imageIterator.GetIndex()[0] < 20) &&
           (imageIterator.GetIndex()[1] > 5 && imageIterator.GetIndex()[1] < 20))
       {
         imageIterator.Set(255);
       }
 
       if ((imageIterator.GetIndex()[0] > 50 && imageIterator.GetIndex()[0] < 70) &&
           (imageIterator.GetIndex()[1] > 50 && imageIterator.GetIndex()[1] < 70))
       {
         imageIterator.Set(60);
       }
       ++imageIterator;
     }
 
     mitk::Image::Pointer image = mitk::ImportItkImage(itkImage);
 
     mitk::IOUtil::Save(image, mitk::IOUtil::CreateTemporaryFile("3Dto2DTestImageXXXXXX.nrrd"));
     mitk::IOUtil::Save(image, mitk::IOUtil::CreateTemporaryFile("3Dto2DTestImageXXXXXX.png"));
   }
 
   /**
   * Try to write a 3D image with only one plane (a 2D images in disguise for all intents and purposes)
   */
   void TestWrite3DImageWithTwoPlanes()
   {
     typedef itk::Image<unsigned char, 3> ImageType;
 
     ImageType::Pointer itkImage = ImageType::New();
 
     ImageType::IndexType start;
     start.Fill(0);
 
     ImageType::SizeType size;
     size[0] = 100;
     size[1] = 100;
     size[2] = 2;
 
     ImageType::RegionType region;
     region.SetSize(size);
     region.SetIndex(start);
     itkImage->SetRegions(region);
     itkImage->Allocate();
     itkImage->FillBuffer(0);
 
     itk::ImageRegionIterator<ImageType> imageIterator(itkImage, itkImage->GetLargestPossibleRegion());
 
     // Make two squares
     while (!imageIterator.IsAtEnd())
     {
       if ((imageIterator.GetIndex()[0] > 5 && imageIterator.GetIndex()[0] < 20) &&
           (imageIterator.GetIndex()[1] > 5 && imageIterator.GetIndex()[1] < 20))
       {
         imageIterator.Set(255);
       }
       if ((imageIterator.GetIndex()[0] > 50 && imageIterator.GetIndex()[0] < 70) &&
           (imageIterator.GetIndex()[1] > 50 && imageIterator.GetIndex()[1] < 70))
       {
         imageIterator.Set(60);
       }
       ++imageIterator;
     }
     mitk::Image::Pointer image = mitk::ImportItkImage(itkImage);
 
     mitk::IOUtil::Save(image, mitk::IOUtil::CreateTemporaryFile("3Dto2DTestImageXXXXXX.nrrd"));
 
     CPPUNIT_ASSERT_THROW(mitk::IOUtil::Save(image, mitk::IOUtil::CreateTemporaryFile("3Dto2DTestImageXXXXXX.png")),
                          mitk::Exception);
   }
 };
 
 MITK_TEST_SUITE_REGISTRATION(mitkItkImageIO)