diff --git a/Filters/Extraction/vtkExtractSelection.cxx b/Filters/Extraction/vtkExtractSelection.cxx
index c254a3def0374695d022043b364cc3c522573930..66e36b26a6c9658b0b26526a5b99d4ba5f33f763 100644
--- a/Filters/Extraction/vtkExtractSelection.cxx
+++ b/Filters/Extraction/vtkExtractSelection.cxx
@@ -20,6 +20,7 @@
 #include "vtkCellData.h"
 #include "vtkCompositeDataSet.h"
 #include "vtkDataSet.h"
+#include "vtkExtractCells.h"
 #include "vtkFrustumSelector.h"
 #include "vtkIdTypeArray.h"
 #include "vtkInformation.h"
@@ -452,107 +453,55 @@ vtkSmartPointer<vtkDataObject> vtkExtractSelection::ExtractElements(
 void vtkExtractSelection::ExtractSelectedCells(
   vtkDataSet* input, vtkUnstructuredGrid* output, vtkSignedCharArray* cellInside)
 {
-  if (!cellInside || cellInside->GetNumberOfTuples() <= 0)
+  const vtkIdType numPts = input->GetNumberOfPoints();
+  const vtkIdType numCells = input->GetNumberOfCells();
+
+  if (!cellInside || cellInside->GetNumberOfTuples() <= 0 ||
+    cellInside->GetNumberOfTuples() != numCells)
   {
     // Assume nothing was selected and return.
     return;
   }
 
-  vtkIdType numPts = input->GetNumberOfPoints();
-  vtkIdType numCells = input->GetNumberOfCells();
-
-  vtkPointData* pd = input->GetPointData();
-  vtkCellData* cd = input->GetCellData();
-  vtkPointData* outputPD = output->GetPointData();
-  vtkCellData* outputCD = output->GetCellData();
-
-  // To copy points in a type agnostic way later
-  auto pointSet = vtkPointSet::SafeDownCast(input);
-
-  vtkNew<vtkPoints> newPts;
-  if (pointSet)
+  // convert insideness array to cell ids to extract.
+  std::vector<vtkIdType> ids;
+  ids.reserve(numCells);
+  for (vtkIdType cc = 0; cc < numCells; ++cc)
   {
-    newPts->SetDataType(pointSet->GetPoints()->GetDataType());
+    if (cellInside->GetValue(cc) != 0)
+    {
+      ids.push_back(cc);
+    }
   }
-  newPts->Allocate(numPts / 4, numPts);
-
-  outputPD->SetCopyGlobalIds(1);
-  outputPD->CopyFieldOff("vtkOriginalPointIds");
-  outputPD->CopyAllocate(pd);
-
-  outputCD->SetCopyGlobalIds(1);
-  outputCD->CopyFieldOff("vtkOriginalCellIds");
-  outputCD->CopyAllocate(cd);
-
-  double x[3];
-
-  vtkNew<vtkIdList> newCellPts;
-  newCellPts->Allocate(VTK_CELL_SIZE);
-
-  // The new point id for each point (-1 for not in selection)
-  std::vector<vtkIdType> pointMap;
-  pointMap.resize(numPts);
-  std::fill(pointMap.begin(), pointMap.end(), -1);
+  ids.shrink_to_fit();
 
+  // The "input" is a shallow copy of the input to this filter and hence we can
+  // modify it. We add original cell ids and point ids arrays.
   vtkNew<vtkIdTypeArray> originalPointIds;
   originalPointIds->SetNumberOfComponents(1);
   originalPointIds->SetName("vtkOriginalPointIds");
-  outputPD->AddArray(originalPointIds);
+  originalPointIds->SetNumberOfTuples(numPts);
+  for (vtkIdType cc = 0; cc < numPts; ++cc)
+  {
+    originalPointIds->SetValue(cc, cc);
+  }
+  input->GetPointData()->AddArray(originalPointIds);
 
   vtkNew<vtkIdTypeArray> originalCellIds;
   originalCellIds->SetNumberOfComponents(1);
   originalCellIds->SetName("vtkOriginalCellIds");
-  outputCD->AddArray(originalCellIds);
-
-  vtkNew<vtkIdList> cellPts;
-
-  for (vtkIdType cellId = 0; cellId < numCells; ++cellId)
+  originalCellIds->SetNumberOfTuples(numCells);
+  for (vtkIdType cc = 0; cc < numCells; ++cc)
   {
-    // 1 means selected, 0 means not selected
-    signed char isInside;
-    assert(cellId < cellInside->GetNumberOfValues());
-    cellInside->GetTypedTuple(cellId, &isInside);
-    if (isInside)
-    {
-      input->GetCellPoints(cellId, cellPts);
-      int cellType = input->GetCellType(cellId);
-      vtkIdType numCellPts = cellPts->GetNumberOfIds();
-      newCellPts->Reset();
-      for (vtkIdType i = 0; i < numCellPts; ++i)
-      {
-        vtkIdType ptId = cellPts->GetId(i);
-        vtkIdType newPointId = pointMap[ptId];
-        if (newPointId < 0)
-        {
-          if (pointSet)
-          {
-            newPointId = newPts->GetNumberOfPoints();
-            newPts->InsertPoints(newPointId, 1, ptId, pointSet->GetPoints());
-          }
-          else
-          {
-            input->GetPoint(ptId, x);
-            newPointId = newPts->InsertNextPoint(x);
-          }
-          outputPD->CopyData(pd, ptId, newPointId);
-          originalPointIds->InsertNextValue(ptId);
-          pointMap[ptId] = newPointId;
-        }
-        newCellPts->InsertId(i, newPointId);
-      }
-      // special handling for polyhedron cells
-      if (vtkUnstructuredGrid::SafeDownCast(input) && cellType == VTK_POLYHEDRON)
-      {
-        newCellPts->Reset();
-        vtkUnstructuredGrid::SafeDownCast(input)->GetFaceStream(cellId, newCellPts);
-        vtkUnstructuredGrid::ConvertFaceStreamPointIds(newCellPts, &pointMap[0]);
-      }
-      vtkIdType newCellId = output->InsertNextCell(cellType, newCellPts);
-      outputCD->CopyData(cd, cellId, newCellId);
-      originalCellIds->InsertNextValue(cellId);
-    }
+    originalCellIds->SetValue(cc, cc);
   }
-  output->SetPoints(newPts);
+  input->GetCellData()->AddArray(originalCellIds);
+
+  vtkNew<vtkExtractCells> extractor;
+  extractor->SetCellIds(&ids.front(), static_cast<vtkIdType>(ids.size()));
+  extractor->SetInputDataObject(input);
+  extractor->Update();
+  output->ShallowCopy(extractor->GetOutput());
 }
 
 //----------------------------------------------------------------------------