diff --git a/IO/HDF/vtkHDFReader.cxx b/IO/HDF/vtkHDFReader.cxx
index 37780b4498c8ba8ef51d40f617ca0576bd45f5a8..6a9eded7d43793b4a536e0ace73e8759fef8f304 100644
--- a/IO/HDF/vtkHDFReader.cxx
+++ b/IO/HDF/vtkHDFReader.cxx
@@ -131,16 +131,53 @@ public:
   }
 };
 
-template <class T>
-bool ReadPolyDataPiece(T* impl, vtkIdType pointOffset, vtkIdType numberOfPoints,
-  std::vector<vtkIdType>& cellOffsets, std::vector<vtkIdType>& numberOfCells,
-  std::vector<vtkIdType>& connectivityOffsets, std::vector<vtkIdType>& numberOfConnectivityIds,
-  vtkPolyData* pieceData)
+template <typename ImplT, typename CacheT>
+vtkSmartPointer<vtkDataArray> ReadFromFileOrCache(ImplT* impl, std::shared_ptr<CacheT> cache,
+  int tag, std::string name, std::string name_modifier, vtkIdType offset, vtkIdType size,
+  bool mData = true)
 {
+  vtkSmartPointer<vtkDataArray> array;
+  std::string cacheName = name + name_modifier;
+  if (cache && cache->CheckExistsAndEqual(tag, cacheName, offset, size))
+  {
+    array = vtkDataArray::SafeDownCast(cache->Get(tag, cacheName));
+    if (!array)
+    {
+      vtkErrorWithObjectMacro(nullptr, "Cannot read the " << cacheName << " array from cache");
+      return nullptr;
+    }
+  }
+  else
+  {
+    array = vtk::TakeSmartPointer(mData ? impl->NewMetadataArray(name.c_str(), offset, size)
+                                        : impl->NewArray(tag, name.c_str(), offset, size));
+    if (!array)
+    {
+      vtkErrorWithObjectMacro(nullptr, "Cannot read the " + cacheName + " array from file");
+      return nullptr;
+    }
+  }
+  if (cache)
+  {
+    cache->Set(tag, name, offset, size, array);
+  }
+  return array;
+}
+
+template <class T, class CacheT>
+bool ReadPolyDataPiece(T* impl, std::shared_ptr<CacheT> cache, vtkIdType pointOffset,
+  vtkIdType numberOfPoints, std::vector<vtkIdType>& cellOffsets,
+  std::vector<vtkIdType>& numberOfCells, std::vector<vtkIdType>& connectivityOffsets,
+  std::vector<vtkIdType>& numberOfConnectivityIds, int filePiece, vtkPolyData* pieceData)
+{
+  auto readFromFileOrCache = [&](int tag, std::string name, vtkIdType offset, vtkIdType size) {
+    std::string modifier = "_" + std::to_string(filePiece);
+    return ReadFromFileOrCache(impl, cache, tag, name, modifier, offset, size);
+  };
   vtkNew<vtkPoints> points;
   vtkSmartPointer<vtkDataArray> pointArray;
-  if ((pointArray = vtk::TakeSmartPointer(
-         impl->NewMetadataArray("Points", pointOffset, numberOfPoints))) == nullptr)
+  if ((pointArray = readFromFileOrCache(
+         ::GEOMETRY_ATTRIBUTE_TAG, "Points", pointOffset, numberOfPoints)) == nullptr)
   {
     vtkErrorWithObjectMacro(nullptr, "Cannot read the Points array");
     return false;
@@ -153,16 +190,15 @@ bool ReadPolyDataPiece(T* impl, vtkIdType pointOffset, vtkIdType numberOfPoints,
   {
     const auto& name = ::POLY_DATA_TOPOS[iTopo];
     vtkSmartPointer<vtkDataArray> offsetsArray;
-    if ((offsetsArray = vtk::TakeSmartPointer(impl->NewMetadataArray(
-           (name + "/Offsets").c_str(), cellOffsets[iTopo], numberOfCells[iTopo] + 1))) == nullptr)
+    if ((offsetsArray = readFromFileOrCache(::GEOMETRY_ATTRIBUTE_TAG, (name + "/Offsets"),
+           cellOffsets[iTopo], numberOfCells[iTopo] + 1)) == nullptr)
     {
       vtkErrorWithObjectMacro(nullptr, "Cannot read the Offsets array for " + name);
       return false;
     }
     vtkSmartPointer<vtkDataArray> connectivityArray;
-    if ((connectivityArray =
-            vtk::TakeSmartPointer(impl->NewMetadataArray((name + "/Connectivity").c_str(),
-              connectivityOffsets[iTopo], numberOfConnectivityIds[iTopo]))) == nullptr)
+    if ((connectivityArray = readFromFileOrCache(::GEOMETRY_ATTRIBUTE_TAG, (name + "/Connectivity"),
+           connectivityOffsets[iTopo], numberOfConnectivityIds[iTopo])) == nullptr)
     {
       vtkErrorWithObjectMacro(nullptr, "Cannot read the Connectivity array for " + name);
       return false;
@@ -254,7 +290,7 @@ private:
 
 //----------------------------------------------------------------------------
 vtkHDFReader::vtkHDFReader()
-  : Cache(new DataCache)
+  : Cache(std::make_shared<DataCache>())
 {
   this->FileName = nullptr;
   // Setup the selection callback to modify this object when an array
@@ -1111,8 +1147,9 @@ int vtkHDFReader::Read(vtkInformation* outInfo, vtkPolyData* data, vtkPartitione
     // populate the poly data piece
     vtkNew<vtkPolyData> pieceData;
     pieceData->Initialize();
-    if (!::ReadPolyDataPiece(this->Impl, pointOffset, numberOfPoints[filePiece], cellOffsets,
-          pieceNumberOfCells, connectivityOffsets, pieceNumberOfConnectivityIds, pieceData))
+    if (!::ReadPolyDataPiece(this->Impl, this->UseCache ? this->Cache : nullptr, pointOffset,
+          numberOfPoints[filePiece], cellOffsets, pieceNumberOfCells, connectivityOffsets,
+          pieceNumberOfConnectivityIds, filePiece, pieceData))
     {
       vtkErrorMacro(
         "There was an error in reading the " << filePiece << " piece of the poly data file.");
@@ -1149,8 +1186,9 @@ int vtkHDFReader::Read(vtkInformation* outInfo, vtkPolyData* data, vtkPartitione
             }
           }
           vtkSmartPointer<vtkDataArray> array;
-          if ((array = vtk::TakeSmartPointer(this->Impl->NewArray(
-                 attributeType, name.c_str(), arrayOffset, numberOf[attributeType]))) == nullptr)
+          if ((array = ::ReadFromFileOrCache(this->Impl, this->UseCache ? this->Cache : nullptr,
+                 attributeType, name, "_" + std::to_string(filePiece), arrayOffset,
+                 numberOf[attributeType], false)) == nullptr)
           {
             vtkErrorMacro("Error reading array " << name);
             return 0;
diff --git a/IO/HDF/vtkHDFReader.h b/IO/HDF/vtkHDFReader.h
index 1f127915d86d1032f87beb04b226adb91c30de35..b6507894a649db8c31aa05da1471478f38952472 100644
--- a/IO/HDF/vtkHDFReader.h
+++ b/IO/HDF/vtkHDFReader.h
@@ -269,7 +269,7 @@ protected:
 
   bool UseCache = false;
   struct DataCache;
-  std::unique_ptr<DataCache> Cache;
+  std::shared_ptr<DataCache> Cache;
 };
 
 VTK_ABI_NAMESPACE_END