diff --git a/Examples/CollisionDetection/ManualCDWithOctree/ManualCDWithOctreeExample.cpp b/Examples/CollisionDetection/ManualCDWithOctree/ManualCDWithOctreeExample.cpp
index 13f2afe1569293885f6a3fc1d1b276f4fc8c6962..b586424f621133e942d2dc699f94f827d760fe55 100644
--- a/Examples/CollisionDetection/ManualCDWithOctree/ManualCDWithOctreeExample.cpp
+++ b/Examples/CollisionDetection/ManualCDWithOctree/ManualCDWithOctreeExample.cpp
@@ -353,7 +353,7 @@ main()
                           const auto numTotalNodes  = octreeCD.getNumAllocatedNodes();
                           const auto numPrimitives  = octreeCD.getPrimitiveCount(OctreePrimitiveType::Point) +
                                                       octreeCD.getPrimitiveCount(OctreePrimitiveType::Triangle) +
-                                                      octreeCD.getPrimitiveCount(OctreePrimitiveType::AnalyticalGeometry);
+                                                      octreeCD.getPrimitiveCount(OctreePrimitiveType::Analytical);
                           const auto maxNumPrimitivesInTree = octreeCD.getMaxNumPrimitivesInNodes();
 
                           // Clear collision debug rendering
diff --git a/Examples/OpenVRController/CMakeLists.txt b/Examples/OpenVRController/CMakeLists.txt
index 3445445c7787261bba49b67bd2e52bdae52285d7..b22e1eee19c3b506f452a976f4960d1e649edaa9 100644
--- a/Examples/OpenVRController/CMakeLists.txt
+++ b/Examples/OpenVRController/CMakeLists.txt
@@ -31,4 +31,4 @@ SET_TARGET_PROPERTIES (${PROJECT_NAME} PROPERTIES FOLDER Examples/OpenVR)
 #-----------------------------------------------------------------------------
 # Link libraries to executable
 #-----------------------------------------------------------------------------
-target_link_libraries(${PROJECT_NAME} SimulationManager apiUtilities)
\ No newline at end of file
+target_link_libraries(${PROJECT_NAME} SimulationManager)
\ No newline at end of file
diff --git a/Examples/Rendering/RenderingExample.cpp b/Examples/Rendering/RenderingExample.cpp
index 80b568bc612c138ad20e6bfc95fd10d1b27df65b..856cf1ccfe9bb5790b5452f1e9c8c6fdabbe44ed 100644
--- a/Examples/Rendering/RenderingExample.cpp
+++ b/Examples/Rendering/RenderingExample.cpp
@@ -117,7 +117,7 @@ main()
 
 #ifdef iMSTK_USE_Vulkan
         // Sphere
-        auto                     sphereObj = apiutils::createVisualAnalyticalSceneObject(Geometry::Type::Sphere, scene, "VisualSphere", 0.025);
+        auto                     sphereObj = apiutils::createVisualAnalyticalSceneObject("Sphere", scene, "VisualSphere", 0.025);
         imstkNew<RenderMaterial> sphereMaterial;
         auto                     sphereMesh = sphereObj->getVisualGeometry();
         sphereMesh->translate(0.1, 0.2, 0.5);
@@ -127,7 +127,7 @@ main()
 #endif
 
         // Plane
-        auto                     planeObj = apiutils::createVisualAnalyticalSceneObject(Geometry::Type::Plane, scene, "VisualPlane", Vec3d(10.0, 10.0, 10.0));
+        auto                     planeObj = apiutils::createVisualAnalyticalSceneObject("Plane", scene, "VisualPlane", Vec3d(10.0, 10.0, 10.0));
         imstkNew<RenderMaterial> planeMaterial;
         planeMaterial->setColor(Color::LightGray);
         planeObj->getVisualModel(0)->setRenderMaterial(planeMaterial);
diff --git a/Examples/SPHFluid/Fluid.hpp b/Examples/SPHFluid/Fluid.hpp
index dc8a240cf1387ae4fc5e25dfbec55f85d7120960..8ebb4fda05435a4593d23a875a01b6d730b0ce3f 100644
--- a/Examples/SPHFluid/Fluid.hpp
+++ b/Examples/SPHFluid/Fluid.hpp
@@ -155,7 +155,7 @@ std::shared_ptr<VecDataArray<double, 3>>
 initializeNonZeroVelocities(const int numParticles)
 {
     imstkNew<VecDataArray<double, 3>> initVelocitiesPtr(numParticles);
-    std::fill_n(initVelocitiesPtr->getPointer(), numParticles, Vec3d(10.0, 0.0, 0.0));
+    initVelocitiesPtr->fill(Vec3d(10.0, 0.0, 0.0));
     return initVelocitiesPtr;
 }
 
diff --git a/Source/Animation/Particles/imstkRenderParticleEmitter.cpp b/Source/Animation/Particles/imstkRenderParticleEmitter.cpp
index d067a31b942041f01e986dca9429e934e267b296..1f5e994b4dde0ded3c408bde95a2ce5c66ccd95f 100644
--- a/Source/Animation/Particles/imstkRenderParticleEmitter.cpp
+++ b/Source/Animation/Particles/imstkRenderParticleEmitter.cpp
@@ -56,7 +56,7 @@ void
 RenderParticleEmitter::setGeometry(
     std::shared_ptr<Geometry> geometry)
 {
-    CHECK(geometry->getType() == Geometry::Type::RenderParticles) << "Geometry must be RenderParticles";
+    CHECK(geometry->getTypeName() == "RenderParticles") << "Geometry must be RenderParticles";
 
     m_animationGeometry = geometry;
     m_particles = &std::static_pointer_cast<RenderParticles>(m_animationGeometry)->getParticles();
diff --git a/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.cpp b/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.cpp
index a29e86c6f131368b1880e0b6fbc7d4aed660ef72..f42e979f14606d8dba4e2980f28ff9b66f99c6f8 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkCollisionDetection.cpp
@@ -20,6 +20,7 @@
 =========================================================================*/
 
 #include "imstkCollisionDetection.h"
+#include "imstkAnalyticalGeometry.h"
 #include "imstkCollisionData.h"
 #include "imstkOctreeBasedCD.h"
 #include "imstkSurfaceMesh.h"
@@ -41,18 +42,18 @@ CollisionDetection::addCollisionPairToOctree(const std::shared_ptr<Geometry>&
                                              const std::shared_ptr<CollisionData>& collisionData)
 {
     auto addToOctree =
-        [&](const std::shared_ptr<Geometry>& geom) {
+        [&](std::shared_ptr<Geometry> geom) {
             if (!s_OctreeCD->hasGeometry(geom->getGlobalIndex()))
             {
-                if (geom->getType() == Geometry::Type::PointSet)
+                if (geom->getTypeName() == "PointSet")
                 {
                     s_OctreeCD->addPointSet(std::dynamic_pointer_cast<PointSet>(geom));
                 }
-                else if (geom->getType() == Geometry::Type::SurfaceMesh)
+                else if (geom->getTypeName() == "SurfaceMesh")
                 {
                     s_OctreeCD->addTriangleMesh(std::dynamic_pointer_cast<SurfaceMesh>(geom));
                 }
-                else
+                else if (std::dynamic_pointer_cast<AnalyticalGeometry>(geom) != nullptr)
                 {
                     s_OctreeCD->addAnalyticalGeometry(geom);
                 }
diff --git a/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCCD.cpp
index da765b9e1978e4eda426d84fc203a65c8d5bc787..942e84243fad6a83b09a86372fca31da4e9d7f24 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCCD.cpp
@@ -34,9 +34,9 @@ ImplicitGeometryToPointSetCCD::ImplicitGeometryToPointSetCCD(std::shared_ptr<Imp
     m_pointSetB(pointSetB)
 {
     centralGrad.setFunction(m_implicitGeomA);
-    if (m_implicitGeomA->getType() == Geometry::Type::SignedDistanceField)
+    if (auto sdf = std::dynamic_pointer_cast<SignedDistanceField>(m_implicitGeomA))
     {
-        centralGrad.setDx(std::dynamic_pointer_cast<SignedDistanceField>(m_implicitGeomA)->getImage()->getSpacing());
+        centralGrad.setDx(sdf->getImage()->getSpacing());
     }
 
     displacementsPtr = std::make_shared<VecDataArray<double, 3>>(static_cast<int>(m_pointSetB->getNumVertices()));
diff --git a/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.cpp
index b3628e5a213c2db0215f12aae58bb7f7edb754dd..9ddcdeace858c43e5eb1576fd252a37c745f3f89 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkImplicitGeometryToPointSetCD.cpp
@@ -38,9 +38,9 @@ ImplicitGeometryToPointSetCD::ImplicitGeometryToPointSetCD(std::shared_ptr<Impli
     m_pointSetB(pointSetB)
 {
     centralGrad.setFunction(m_implicitGeomA);
-    if (m_implicitGeomA->getType() == Geometry::Type::SignedDistanceField)
+    if (auto sdf = std::dynamic_pointer_cast<SignedDistanceField>(m_implicitGeomA))
     {
-        centralGrad.setDx(std::dynamic_pointer_cast<SignedDistanceField>(m_implicitGeomA)->getImage()->getSpacing() * 0.5);
+        centralGrad.setDx(sdf->getImage()->getSpacing() * 0.5);
     }
 }
 
diff --git a/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp
index eec2f1f7946c07b53f2658097467096f15ae8904..c8a24faf2b419a5130e7dee052a1589bc9488be4 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkMeshToMeshBruteForceCD.cpp
@@ -47,17 +47,17 @@ MeshToMeshBruteForceCD::computeCollisionData()
     doBroadPhaseCollisionCheck();
 
     // Narrow phase collision
-    const auto                     mesh2         = std::static_pointer_cast<SurfaceMesh>(m_object2);
+    const auto                     mesh2         = std::dynamic_pointer_cast<SurfaceMesh>(m_object2);
     const VecDataArray<int, 3>&    mesh2Cells    = *mesh2->getTriangleIndices();
     const VecDataArray<double, 3>& mesh2Vertices = *mesh2->getVertexPositions();
 
-    if (m_object1->getType() == Geometry::Type::LineMesh)
+    if (m_object1->getTypeName() == "LineMesh")
     {
-        auto                           mesh1 = std::static_pointer_cast<LineMesh>(m_object1);
-        const VecDataArray<double, 3>& mesh1Vertices = *mesh1->getVertexPositions();
+        auto                           lineMesh      = std::dynamic_pointer_cast<LineMesh>(m_object1);
+        const VecDataArray<double, 3>& mesh1Vertices = *lineMesh->getVertexPositions();
 
         // brute force, use BVH or spatial grid would be much better
-        for (int i = 0; i < static_cast<int>(mesh1->getNumVertices()); ++i)
+        for (int i = 0; i < static_cast<int>(lineMesh->getNumVertices()); ++i)
         {
             const Vec3d p = mesh1Vertices[i];
 
@@ -80,13 +80,13 @@ MeshToMeshBruteForceCD::computeCollisionData()
             }
         }
 
-        const int                      numLines    = static_cast<int>(mesh1->getNumLines());
+        const int                      numLines    = static_cast<int>(lineMesh->getNumLines());
         const int                      numVertices = static_cast<int>(mesh2->getNumVertices());
         std::vector<std::vector<bool>> E2(numVertices, std::vector<bool>(numVertices, 1));
 
         for (int k = 0; k < numLines; ++k)
         {
-            const Vec2i& nodes = mesh1->getLineIndices(k);
+            const Vec2i& nodes = lineMesh->getLineIndices(k);
             const size_t i1    = nodes[0];
             const size_t i2    = nodes[1];
 
@@ -138,14 +138,14 @@ MeshToMeshBruteForceCD::computeCollisionData()
             }
         }
     }
-    else if (m_object1->getType() == Geometry::Type::PointSet)
+    else if (m_object1->getTypeName() == "PointSet")
     {
-        const auto                     mesh1 = std::static_pointer_cast<PointSet>(m_object1);
-        const VecDataArray<double, 3>& mesh1Vertices = *mesh1->getVertexPositions();
+        auto                           pointSet      = std::dynamic_pointer_cast<PointSet>(m_object1);
+        const VecDataArray<double, 3>& mesh1Vertices = *pointSet->getVertexPositions();
 
         // brute force, use BVH or spatial grid would be much better
         // point
-        for (int i = 0; i < static_cast<int>(mesh1->getNumVertices()); ++i)
+        for (int i = 0; i < static_cast<int>(pointSet->getNumVertices()); ++i)
         {
             const auto p = mesh1Vertices[i];
 
@@ -166,15 +166,15 @@ MeshToMeshBruteForceCD::computeCollisionData()
             }
         }
     }
-    else
+    else if (m_object1->getTypeName() == "SurfaceMesh")
     {
-        const auto                     mesh1 = std::static_pointer_cast<SurfaceMesh>(m_object1);
-        const VecDataArray<double, 3>& mesh1Vertices = *mesh1->getVertexPositions();
-        const VecDataArray<int, 3>&    mesh1Cells    = *mesh1->getTriangleIndices();
+        auto                           surfMesh      = std::dynamic_pointer_cast<SurfaceMesh>(m_object1);
+        const VecDataArray<double, 3>& mesh1Vertices = *surfMesh->getVertexPositions();
+        const VecDataArray<int, 3>&    mesh1Cells    = *surfMesh->getTriangleIndices();
 
         // brute force, use BVH or spatial grid would be much better
         // point
-        for (int i = 0; i < static_cast<int>(mesh1->getNumVertices()); ++i)
+        for (int i = 0; i < static_cast<int>(surfMesh->getNumVertices()); ++i)
         {
             const Vec3d p = mesh1Vertices[i];
 
@@ -197,7 +197,7 @@ MeshToMeshBruteForceCD::computeCollisionData()
 
         // edge
         // since we don't have edge structure, the following is not good
-        const auto                     nV = mesh1->getNumVertices();
+        const auto                     nV = surfMesh->getNumVertices();
         std::vector<std::vector<bool>> E(nV, std::vector<bool>(nV, 1));
 
         const auto                     nV2 = mesh2->getNumVertices();
@@ -317,8 +317,8 @@ MeshToMeshBruteForceCD::computeCollisionData()
             i2 = tri[0];
             if (E[i1][i2] && E[i2][i1])
             {
-                const Vec3d P = mesh1->getVertexPosition(i1);
-                const Vec3d Q = mesh1->getVertexPosition(i2);
+                const Vec3d P = surfMesh->getVertexPosition(i1);
+                const Vec3d Q = surfMesh->getVertexPosition(i2);
                 for (int j = 0; j < mesh2Cells.size(); ++j)
                 {
                     const Vec3i& e  = mesh2Cells[j];
diff --git a/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.cpp b/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.cpp
index cf9da3d9ededae4f4771c34dff4641bcdeb749d5..89d4256c54361cec82e2b8e91ee49ab83accf62c 100644
--- a/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.cpp
+++ b/Source/CollisionDetection/CollisionDetection/imstkOctreeBasedCD.cpp
@@ -60,29 +60,29 @@ OctreeBasedCD::addCollisionPair(const std::shared_ptr<Geometry>& geom1, const st
     m_mCollisionPair2AssociatedData[collisionPair] = { collisionType, collisionData };
     m_vCollidingGeomPairs.push_back({ geom1.get(), geom2.get() });
 
-    const auto geomType1 = geom1->getType();
-    const auto geomType2 = geom2->getType();
+    const std::string geomType1 = geom1->getTypeName();
+    const std::string geomType2 = geom2->getTypeName();
 
-    if (geomType1 == Geometry::Type::PointSet
-        || geomType2 == Geometry::Type::PointSet)
+    if (geomType1 == "PointSet"
+        || geomType2 == "PointSet")
     {
         const uint32_t mask = 1 << static_cast<int>(OctreePrimitiveType::Point);
         m_sCollidingPrimitiveTypes |= mask;
     }
 
-    if (geomType1 == Geometry::Type::SurfaceMesh
-        || geomType2 == Geometry::Type::SurfaceMesh)
+    if (geomType1 == "SurfaceMesh"
+        || geomType2 == "SurfaceMesh")
     {
         const uint32_t mask = 1 << static_cast<int>(OctreePrimitiveType::Triangle);
         m_sCollidingPrimitiveTypes |= mask;
     }
 
-    if (geomType1 != Geometry::Type::PointSet
-        || geomType2 != Geometry::Type::PointSet
-        || geomType1 != Geometry::Type::SurfaceMesh
-        || geomType2 != Geometry::Type::SurfaceMesh)
+    if (geomType1 != "PointSet"
+        || geomType2 != "PointSet"
+        || geomType1 != "SurfaceMesh"
+        || geomType2 != "SurfaceMesh")
     {
-        const uint32_t mask = 1 << static_cast<int>(OctreePrimitiveType::AnalyticalGeometry);
+        const uint32_t mask = 1 << static_cast<int>(OctreePrimitiveType::Analytical);
         m_sCollidingPrimitiveTypes |= mask;
     }
 
@@ -145,7 +145,7 @@ OctreeBasedCD::detectCollision()
     for (auto& geoPair: m_vCollidingGeomPairs)
     {
         // Ignore the collision pair if it is not a PointSet-SurfaceMesh pair
-        if (geoPair.first->getType() != Geometry::Type::PointSet || (geoPair.second->getType() != Geometry::Type::SurfaceMesh))
+        if (geoPair.first->getTypeName() != "PointSet" || (geoPair.second->getTypeName() != "SurfaceMesh"))
         {
             continue;
         }
diff --git a/Source/DataStructures/Testing/imstkLooseOctreeTest.cpp b/Source/DataStructures/Testing/imstkLooseOctreeTest.cpp
index ea008e67fd2c94eed56fbcf7b34fba0e125ee046..fa5c2bfeba3bb587f3688acfd15b81e15d0d876a 100644
--- a/Source/DataStructures/Testing/imstkLooseOctreeTest.cpp
+++ b/Source/DataStructures/Testing/imstkLooseOctreeTest.cpp
@@ -166,13 +166,13 @@ public:
         m_Octree->addPointSet(m_PointSet);
         EXPECT_EQ(m_Octree->m_vPrimitivePtrs[OctreePrimitiveType::Point].size(), m_PointSet->getNumVertices());
         EXPECT_EQ(m_Octree->m_vPrimitivePtrs[OctreePrimitiveType::Triangle].size(), 0);
-        EXPECT_EQ(m_Octree->m_vPrimitivePtrs[OctreePrimitiveType::AnalyticalGeometry].size(), 0);
+        EXPECT_EQ(m_Octree->m_vPrimitivePtrs[OctreePrimitiveType::Analytical].size(), 0);
 
         m_Mesh = generateMesh();
         m_Octree->addTriangleMesh(m_Mesh);
         EXPECT_EQ(m_Octree->m_vPrimitivePtrs[OctreePrimitiveType::Point].size(), m_PointSet->getNumVertices());
         EXPECT_EQ(m_Octree->m_vPrimitivePtrs[OctreePrimitiveType::Triangle].size(), m_Mesh->getNumTriangles());
-        EXPECT_EQ(m_Octree->m_vPrimitivePtrs[OctreePrimitiveType::AnalyticalGeometry].size(), 0);
+        EXPECT_EQ(m_Octree->m_vPrimitivePtrs[OctreePrimitiveType::Analytical].size(), 0);
 
         m_Octree->build();
     }
@@ -252,7 +252,7 @@ public:
                 for (const auto& pPrimitive : m_Octree->m_vPrimitivePtrs[i])
                 {
                     const auto pNode = pPrimitive->m_pNode;
-                    if (pPrimitive->m_pGeometry->getType() == Geometry::Type::PointSet)
+                    if (pPrimitive->m_pGeometry->getTypeName() == "PointSet")
                     {
                         EXPECT_EQ(pNode->looselyContains(pPrimitive->m_Position), true);
                     }
diff --git a/Source/DataStructures/imstkLooseOctree.cpp b/Source/DataStructures/imstkLooseOctree.cpp
index b066fbc43cfffd88d12f9376deb6fe2d38c49b4d..d28c6cc873958fdb6b016504ec74e8e374f3719f 100644
--- a/Source/DataStructures/imstkLooseOctree.cpp
+++ b/Source/DataStructures/imstkLooseOctree.cpp
@@ -334,7 +334,7 @@ OctreeNode::updateDebugGeometry()
     // No primitive in this node
     if (m_PrimitiveCounts[OctreePrimitiveType::Point] == 0
         && m_PrimitiveCounts[OctreePrimitiveType::Triangle] == 0
-        && m_PrimitiveCounts[OctreePrimitiveType::AnalyticalGeometry] == 0)
+        && m_PrimitiveCounts[OctreePrimitiveType::Analytical] == 0)
     {
         if (!m_pTree->m_bDrawNonEmptyParent)
         {
@@ -526,7 +526,7 @@ uint32_t
 LooseOctree::addAnalyticalGeometry(const std::shared_ptr<Geometry>& geometry)
 {
     // Type alias, to reduce copy/past errors
-    static const auto type = static_cast<int>(OctreePrimitiveType::AnalyticalGeometry);
+    static const auto type = static_cast<int>(OctreePrimitiveType::Analytical);
 
     const auto pGeometry = geometry.get();
     const auto geomIdx   = pGeometry->getGlobalIndex();
@@ -572,10 +572,10 @@ LooseOctree::build()
     // Compute the minimum bounding box of non-point primitives
     if (m_vPrimitivePtrs[OctreePrimitiveType::Point].size() == 0
         && (m_vPrimitivePtrs[OctreePrimitiveType::Triangle].size() > 0
-            || m_vPrimitivePtrs[OctreePrimitiveType::AnalyticalGeometry].size() > 0))
+            || m_vPrimitivePtrs[OctreePrimitiveType::Analytical].size() > 0))
     {
         Real minWidth = MAX_REAL;
-        for (int type = OctreePrimitiveType::Triangle; type <= OctreePrimitiveType::AnalyticalGeometry; ++type)
+        for (int type = OctreePrimitiveType::Triangle; type <= OctreePrimitiveType::Analytical; ++type)
         {
             const auto& vPrimitivePtrs = m_vPrimitivePtrs[type];
             if (vPrimitivePtrs.size() == 0)
@@ -665,7 +665,7 @@ LooseOctree::rebuild()
     // Populate all primitives to tree nodes in a top-down manner
     populatePointPrimitives();
     populateNonPointPrimitives(OctreePrimitiveType::Triangle);
-    populateNonPointPrimitives(OctreePrimitiveType::AnalyticalGeometry);
+    populateNonPointPrimitives(OctreePrimitiveType::Analytical);
 }
 
 void
@@ -709,7 +709,7 @@ LooseOctree::incrementalUpdate()
     // Then, check their validity (valid primitive = it is still loosely contained in the node's bounding box)
     updatePositionAndCheckValidity();
     updateBoundingBoxAndCheckValidity(OctreePrimitiveType::Triangle);
-    updateBoundingBoxAndCheckValidity(OctreePrimitiveType::AnalyticalGeometry);
+    updateBoundingBoxAndCheckValidity(OctreePrimitiveType::Analytical);
 
     // Remove all invalid primitives from tree nodes
     removeInvalidPrimitivesFromNodes();
@@ -717,7 +717,7 @@ LooseOctree::incrementalUpdate()
     // Insert the invalid primitives back to the tree
     reinsertInvalidPrimitives(OctreePrimitiveType::Point);
     reinsertInvalidPrimitives(OctreePrimitiveType::Triangle);
-    reinsertInvalidPrimitives(OctreePrimitiveType::AnalyticalGeometry);
+    reinsertInvalidPrimitives(OctreePrimitiveType::Analytical);
 
     // Recursively remove all empty nodes, returning them to memory pool for recycling
     m_pRootNode->removeEmptyDescendants();
diff --git a/Source/DataStructures/imstkLooseOctree.h b/Source/DataStructures/imstkLooseOctree.h
index 846f4da5d365a05b2e689a566aae2065adcb1d57..a01c3d11b44cc1b3cfa50379d93d6dcf39accf8d 100644
--- a/Source/DataStructures/imstkLooseOctree.h
+++ b/Source/DataStructures/imstkLooseOctree.h
@@ -48,7 +48,7 @@ enum OctreePrimitiveType
 {
     Point = 0,
     Triangle,
-    AnalyticalGeometry,
+    Analytical,
     NumPrimitiveTypes
 };
 
diff --git a/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.cpp b/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.cpp
index 7264f71fa8c33601aa358b3d8d99751b19bcd454..1f60354223d5540b41dbde0eca8a5a4494937c2e 100644
--- a/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.cpp
@@ -42,7 +42,7 @@ AbstractDynamicalModel::isGeometryValid(const std::shared_ptr<Geometry> geometry
         }
 
         // If it exists in the set then it is valid geometry
-        if (m_validGeometryTypes.count(geometry->getType()))
+        if (m_validGeometryTypes.count(geometry->getTypeName()))
         {
             return true;
         }
diff --git a/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.h b/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.h
index 79c19c966fe0dba467531b76ff1d5304e02fad4b..a92ad6d699a097aa882819cdd1b5ef42625019a5 100644
--- a/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.h
+++ b/Source/DynamicalModels/ObjectModels/imstkAbstractDynamicalModel.h
@@ -155,7 +155,7 @@ protected:
     std::size_t m_numDOF;                           ///> Total number of degree of freedom
 
     std::shared_ptr<Geometry> m_geometry = nullptr; ///> Physics geometry of the model
-    std::set<Geometry::Type>  m_validGeometryTypes; ///> Valid geometry types of this model
+    std::set<std::string>     m_validGeometryTypes; ///> Valid geometry types of this model
 
     TimeSteppingType m_timeStepSizeType = TimeSteppingType::Fixed;
 
diff --git a/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp b/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp
index f840200f6abdebcee8f4da6eedcaad89b4b18f55..46db618c35231cf0fdae47719295a5be7bedc075 100644
--- a/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkFEMDeformableBodyModel.cpp
@@ -53,10 +53,7 @@ FEMDeformableBodyModel::FEMDeformableBodyModel() :
 {
     m_fixedNodeIds.reserve(1000);
 
-    m_validGeometryTypes = {
-        Geometry::Type::TetrahedralMesh,
-        Geometry::Type::HexahedralMesh
-    };
+    m_validGeometryTypes = { "TetrahedralMesh", "HexahedralMesh" };
 
     m_solveNode = m_taskGraph->addFunction("FEMModel_Solve", [&]() { getSolver()->solve(); });
 }
diff --git a/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.cpp b/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.cpp
index dcec520d0ac64798388d40fcbc8136a5084a1196..0930c42d60ab2a6b85073c6528175230666761b1 100644
--- a/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkLevelSetModel.cpp
@@ -31,10 +31,7 @@ namespace imstk
 LevelSetModel::LevelSetModel()
 {
     // If given an image data
-    m_validGeometryTypes = {
-        Geometry::Type::ImageData,
-        Geometry::Type::SignedDistanceField
-    };
+    m_validGeometryTypes = { "ImageData", "SignedDistanceField" };
 
     // By default the level set defines a function for evolving the distances, this can be removed in subclasses
     m_evolveQuantitiesNodes.push_back(std::make_shared<TaskNode>(std::bind(&LevelSetModel::evolve, this), "Evolve Distances"));
@@ -51,15 +48,15 @@ LevelSetModel::initialize()
         return false;
     }
 
-    if (m_geometry->getType() == Geometry::Type::ImageData)
+    if (auto imageData = std::dynamic_pointer_cast<ImageData>(m_geometry))
     {
-        if (std::dynamic_pointer_cast<ImageData>(m_geometry)->getScalarType() != IMSTK_DOUBLE)
+        if (imageData->getScalarType() != IMSTK_DOUBLE)
         {
             LOG(WARNING) << "Levelset only works with double image types";
             return false;
         }
 
-        m_mesh = std::make_shared<SignedDistanceField>(std::dynamic_pointer_cast<ImageData>(m_geometry));
+        m_mesh = std::make_shared<SignedDistanceField>(imageData);
     }
     else
     {
@@ -69,9 +66,8 @@ LevelSetModel::initialize()
     m_backwardGrad.setFunction(m_mesh);
     m_curvature.setFunction(m_mesh);
 
-    if (m_mesh->getType() == Geometry::Type::SignedDistanceField)
+    if (auto sdf = std::dynamic_pointer_cast<SignedDistanceField>(m_mesh))
     {
-        auto                       sdf      = std::dynamic_pointer_cast<SignedDistanceField>(m_mesh);
         std::shared_ptr<ImageData> sdfImage = sdf->getImage();
         if (!m_config->m_sparseUpdate)
         {
@@ -83,7 +79,6 @@ LevelSetModel::initialize()
 
             m_velocities = std::make_shared<ImageData>();
             m_velocities->allocate(IMSTK_DOUBLE, 1, sdfImage->getDimensions(), sdfImage->getSpacing(), sdfImage->getOrigin());
-            //std::fill_n(static_cast<double*>(m_velocities->getScalars()->getVoidPointer()), m_velocities->get
         }
 
         const Vec3d actualSpacing = sdf->getImage()->getSpacing();// *sdf->getScale();
@@ -110,7 +105,6 @@ LevelSetModel::evolve()
     auto         imageData = std::dynamic_pointer_cast<ImageData>(sdf->getImage());
     double*      imgPtr    = static_cast<double*>(imageData->getVoidPointer());
     const Vec3i& dim       = imageData->getDimensions();
-    const Vec3d& spacing   = imageData->getSpacing();
     const double dt = m_config->m_dt / m_config->m_substeps;
     //const double k  = m_config->m_k;
 
diff --git a/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp b/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp
index e720d34d437abdcea3466593eec02f7987d4679c..01e572c09df335eb150603385d4bc07d81d268bf 100644
--- a/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkPbdModel.cpp
@@ -45,11 +45,11 @@ PbdModel::PbdModel() : DynamicalModel(DynamicalModelType::PositionBasedDynamics)
     m_parameters(std::make_shared<PBDModelConfig>())
 {
     m_validGeometryTypes = {
-        Geometry::Type::PointSet,
-        Geometry::Type::LineMesh,
-        Geometry::Type::SurfaceMesh,
-        Geometry::Type::TetrahedralMesh,
-        Geometry::Type::HexahedralMesh
+        "PointSet",
+        "LineMesh",
+        "SurfaceMesh",
+        "TetrahedralMesh",
+        "HexahedralMesh"
     };
 
     // Setup PBD compute nodes
@@ -298,7 +298,7 @@ bool
 PbdModel::initializeFEMConstraints(PbdFEMConstraint::MaterialType type)
 {
     // Check if constraint type matches the mesh type
-    CHECK(m_mesh->getType() == Geometry::Type::TetrahedralMesh)
+    CHECK(m_mesh->getTypeName() == "TetrahedralMesh")
         << "FEM Tetrahedral constraint should come with tetrahedral mesh";
 
     // Create constraints
@@ -324,7 +324,8 @@ bool
 PbdModel::initializeVolumeConstraints(const double stiffness)
 {
     // Check if constraint type matches the mesh type
-    CHECK(m_mesh->getType() == Geometry::Type::TetrahedralMesh) << "Volume constraint should come with volumetric mesh";
+    CHECK(m_mesh->getTypeName() == "TetrahedralMesh")
+        << "Volume constraint should come with volumetric mesh";
 
     // Create constraints
     const auto&                 tetMesh  = std::static_pointer_cast<TetrahedralMesh>(m_mesh);
@@ -364,7 +365,7 @@ PbdModel::initializeDistanceConstraints(const double stiffness)
             }
         };
 
-    if (m_mesh->getType() == Geometry::Type::TetrahedralMesh)
+    if (m_mesh->getTypeName() == "TetrahedralMesh")
     {
         const auto&                    tetMesh  = std::static_pointer_cast<TetrahedralMesh>(m_mesh);
         const VecDataArray<int, 4>&    elements = *tetMesh->getTetrahedraIndices();
@@ -382,7 +383,7 @@ PbdModel::initializeDistanceConstraints(const double stiffness)
             addConstraint(E, tet[2], tet[3]);
         }
     }
-    else if (m_mesh->getType() == Geometry::Type::SurfaceMesh)
+    else if (m_mesh->getTypeName() == "SurfaceMesh")
     {
         const auto&                    triMesh  = std::static_pointer_cast<SurfaceMesh>(m_mesh);
         const VecDataArray<int, 3>&    elements = *triMesh->getTriangleIndices();
@@ -397,7 +398,7 @@ PbdModel::initializeDistanceConstraints(const double stiffness)
             addConstraint(E, tri[1], tri[2]);
         }
     }
-    else if (m_mesh->getType() == Geometry::Type::LineMesh)
+    else if (m_mesh->getTypeName() == "LineMesh")
     {
         const auto&                    lineMesh = std::static_pointer_cast<LineMesh>(m_mesh);
         const VecDataArray<int, 2>&    elements = *lineMesh->getLinesIndices();
@@ -418,7 +419,7 @@ bool
 PbdModel::initializeAreaConstraints(const double stiffness)
 {
     // check if constraint type matches the mesh type
-    CHECK(m_mesh->getType() == Geometry::Type::SurfaceMesh)
+    CHECK(m_mesh->getTypeName() == "SurfaceMesh")
         << "Area constraint should come with a triangular mesh";
 
     // ok, now create constraints
@@ -442,7 +443,8 @@ PbdModel::initializeAreaConstraints(const double stiffness)
 bool
 PbdModel::initializeBendConstraints(const double stiffness)
 {
-    CHECK(m_mesh->getType() == Geometry::Type::LineMesh) << "Bend constraint should come with a line mesh";
+    CHECK(m_mesh->getTypeName() == "LineMesh")
+        << "Bend constraint should come with a line mesh";
 
     auto addConstraint =
         [&](const double k, size_t i1, size_t i2, size_t i3)
@@ -485,7 +487,8 @@ PbdModel::initializeBendConstraints(const double stiffness)
 bool
 PbdModel::initializeDihedralConstraints(const double stiffness)
 {
-    CHECK(m_mesh->getType() == Geometry::Type::SurfaceMesh) << "Dihedral constraint should come with a triangular mesh";
+    CHECK(m_mesh->getTypeName() == "SurfaceMesh")
+        << "Dihedral constraint should come with a triangular mesh";
 
     // Create constraints
     const auto&                      triMesh  = std::static_pointer_cast<SurfaceMesh>(m_mesh);
@@ -560,11 +563,7 @@ bool
 PbdModel::initializeConstantDensityConstraint(const double stiffness)
 {
     // check if constraint type matches the mesh type
-    CHECK(m_mesh->getType() == Geometry::Type::SurfaceMesh
-        || m_mesh->getType() == Geometry::Type::TetrahedralMesh
-        || m_mesh->getType() == Geometry::Type::LineMesh
-        || m_mesh->getType() == Geometry::Type::HexahedralMesh
-        || m_mesh->getType() == Geometry::Type::PointSet)
+    CHECK(std::dynamic_pointer_cast<PointSet>(m_mesh) != nullptr)
         << "Constant constraint should come with a mesh!";
 
     auto c = std::make_shared<PbdConstantDensityConstraint>();
diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp
index 91442663f190223cedf9a547180283e9452ece4f..7f7a201fd08e51318b753a98e78a34b3e97213ba 100644
--- a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.cpp
@@ -43,30 +43,22 @@ RigidBodyModel::initialize()
         m_initialState->setPosition(m_geometry->getTranslation());
         m_currentState->setPosition(m_geometry->getTranslation());
 
-        switch (m_geometry->getType())
-        {
-        case Geometry::Type::Sphere:
+        const std::string geomType = m_geometry->getTypeName();
+        if (geomType == "Sphere")
         {
             createSphere();
-            break;
         }
-        case Geometry::Type::Cube:
+        else if (geomType == "Cube")
         {
             createCube();
-            break;
         }
-        case Geometry::Type::Plane:
+        else if (geomType == "Plane")
         {
             createPlane();
-            break;
         }
-        case Geometry::Type::SurfaceMesh:
-
+        else if (geomType == "SurfaceMesh")
+        {
             createMesh();
-            break;
-
-        default:
-            break;
         }
 
         /*if (m_pxDynamicActor)
diff --git a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h
index cdf170c9a05506d5ce836a14d0acf75a7debeed9..af70c4dc49ae876f0d40583df94744e542389939 100644
--- a/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h
+++ b/Source/DynamicalModels/ObjectModels/imstkRigidBodyModel.h
@@ -61,14 +61,15 @@ public:
     {
         m_validGeometryTypes =
         {
-            Geometry::Type::Plane,
-            Geometry::Type::Sphere,
-            Geometry::Type::Cube,
-            Geometry::Type::SurfaceMesh
+            "Plane",
+            "Sphere",
+            "Cube",
+            "SurfaceMesh"
         };
     };
     virtual ~RigidBodyModel() override = default;
 
+public:
     ///
     /// \brief Initialize the physx dynamic model
     ///
diff --git a/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp b/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp
index e9b3f59b35bd59bf9061227f2c392eee2411a4ed..fbb7b9cd28d479c2c3e6c0e8776c375aa5630ecc 100644
--- a/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp
+++ b/Source/DynamicalModels/ObjectModels/imstkSPHModel.cpp
@@ -94,7 +94,7 @@ SPHModelConfig::initialize()
 
 SPHModel::SPHModel() : DynamicalModel<SPHState>(DynamicalModelType::SmoothedParticleHydrodynamics)
 {
-    m_validGeometryTypes = { Geometry::Type::PointSet };
+    m_validGeometryTypes = { "PointSet" };
 
     m_findParticleNeighborsNode = m_taskGraph->addFunction("SPHModel_Partition", std::bind(&SPHModel::findParticleNeighbors, this));
     m_computeDensityNode = m_taskGraph->addFunction("SPHModel_ComputeDensity", [&]()
diff --git a/Source/Filtering/imstkCleanMesh.cpp b/Source/Filtering/imstkCleanMesh.cpp
index 36d250e8f838f754190a3ccf6d34ee8c2c461083..9da413138b7eb46f9eab6be31ce705728890084b 100644
--- a/Source/Filtering/imstkCleanMesh.cpp
+++ b/Source/Filtering/imstkCleanMesh.cpp
@@ -58,13 +58,13 @@ CleanMesh::requestUpdate()
         return;
     }
     vtkSmartPointer<vtkPolyData> inputMeshVtk = nullptr;
-    if (inputMesh->getType() == Geometry::Type::LineMesh)
+    if (auto lineMesh = std::dynamic_pointer_cast<LineMesh>(inputMesh))
     {
-        inputMeshVtk = GeometryUtils::copyToVtkPolyData(std::dynamic_pointer_cast<LineMesh>(inputMesh));
+        inputMeshVtk = GeometryUtils::copyToVtkPolyData(lineMesh);
     }
-    else if (inputMesh->getType() == Geometry::Type::SurfaceMesh)
+    else if (auto surfMesh = std::dynamic_pointer_cast<SurfaceMesh>(inputMesh))
     {
-        inputMeshVtk = GeometryUtils::copyToVtkPolyData(std::dynamic_pointer_cast<SurfaceMesh>(inputMesh));
+        inputMeshVtk = GeometryUtils::copyToVtkPolyData(surfMesh);
     }
     else
     {
@@ -79,11 +79,11 @@ CleanMesh::requestUpdate()
     filter->SetToleranceIsAbsolute(m_UseAbsolute);
     filter->Update();
 
-    if (inputMesh->getType() == Geometry::Type::LineMesh)
+    if (std::dynamic_pointer_cast<LineMesh>(inputMesh) != nullptr)
     {
         setOutput(GeometryUtils::copyToLineMesh(filter->GetOutput()));
     }
-    else if (inputMesh->getType() == Geometry::Type::SurfaceMesh)
+    else if (std::dynamic_pointer_cast<SurfaceMesh>(inputMesh) != nullptr)
     {
         setOutput(GeometryUtils::copyToSurfaceMesh(filter->GetOutput()));
     }
diff --git a/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp b/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp
index f2c85208099161506ce3f284b9f658ca2297bc55..1cea393266a5cd065a1481bf1e66b03df5fc30af 100644
--- a/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp
+++ b/Source/Geometry/Analytic/imstkAnalyticalGeometry.cpp
@@ -24,7 +24,7 @@
 
 namespace imstk
 {
-AnalyticalGeometry::AnalyticalGeometry(Type type, const std::string& name) : ImplicitGeometry(type, name),
+AnalyticalGeometry::AnalyticalGeometry(const std::string& name) : ImplicitGeometry(name),
     m_position(WORLD_ORIGIN), m_positionPostTransform(WORLD_ORIGIN),
     m_orientationAxis(UP_VECTOR), m_orientationAxisPostTransform(UP_VECTOR)
 {
diff --git a/Source/Geometry/Analytic/imstkAnalyticalGeometry.h b/Source/Geometry/Analytic/imstkAnalyticalGeometry.h
index 925e6a717b17f17338b2fb6be96297d9a7768e0d..d96f06427628fc8c17d2a6757745b504cb2c7689 100644
--- a/Source/Geometry/Analytic/imstkAnalyticalGeometry.h
+++ b/Source/Geometry/Analytic/imstkAnalyticalGeometry.h
@@ -32,6 +32,9 @@ namespace imstk
 ///
 class AnalyticalGeometry : public ImplicitGeometry
 {
+public:
+    virtual ~AnalyticalGeometry() override = default;
+
 public:
     ///
     /// \brief Print
@@ -56,7 +59,7 @@ public:
     double getFunctionValue(const Vec3d& imstkNotUsed(pos)) const override { return 0.0; }
 
 protected:
-    explicit AnalyticalGeometry(Type type, const std::string& name = std::string(""));
+    AnalyticalGeometry(const std::string& name = std::string(""));
 
     virtual void applyTransform(const Mat4d& m) override;
     virtual void updatePostTransformData() const override;
diff --git a/Source/Geometry/Analytic/imstkCapsule.h b/Source/Geometry/Analytic/imstkCapsule.h
index a1bcc0dc2592c4858d3e577a7deecc513e5f098c..3ed969530c6a2c7732faeb1f8fb87296388e2a50 100644
--- a/Source/Geometry/Analytic/imstkCapsule.h
+++ b/Source/Geometry/Analytic/imstkCapsule.h
@@ -36,9 +36,17 @@ public:
     ///
     /// \brief Constructor
     ///
-    Capsule(const std::string& name = std::string("defaultCapsule")) : AnalyticalGeometry(Type::Capsule, name) {}
+    Capsule(const std::string& name = std::string("defaultCapsule")) : AnalyticalGeometry(name) { }
 
-    ~Capsule() override = default;
+    ///
+    /// \brief Deconstructor
+    ///
+    virtual ~Capsule() override = default;
+
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "Capsule"; }
 
 public:
     ///
diff --git a/Source/Geometry/Analytic/imstkCube.h b/Source/Geometry/Analytic/imstkCube.h
index 2ac49400ef44dd3414a62f196d98ccb0624df018..5edd398dfccc9ac3e1a4254822d3e02d2444f72b 100644
--- a/Source/Geometry/Analytic/imstkCube.h
+++ b/Source/Geometry/Analytic/imstkCube.h
@@ -35,15 +35,20 @@ class Cube;
 class Cube : public AnalyticalGeometry
 {
 public:
-    explicit Cube(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double width = 1.0, const Vec3d& orientationAxis = Vec3d(0.0, 1.0, 0.0),
-                  const std::string& name = std::string("defaultCube")) : AnalyticalGeometry(Type::Cube, name)
+    Cube(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double width = 1.0, const Vec3d& orientationAxis = Vec3d(0.0, 1.0, 0.0),
+         const std::string& name = std::string("defaultCube")) : AnalyticalGeometry(name)
     {
         setPosition(pos);
         setOrientationAxis(orientationAxis);
         setWidth(width);
     }
 
-    ~Cube() override = default;
+    virtual ~Cube() override = default;
+
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "Cube"; }
 
 public:
     ///
diff --git a/Source/Geometry/Analytic/imstkCylinder.h b/Source/Geometry/Analytic/imstkCylinder.h
index 2fe199ce76b0fdd310de4933b229de1296faf1e5..61038b1a0ace8a60f78705770cc07be519218fcc 100644
--- a/Source/Geometry/Analytic/imstkCylinder.h
+++ b/Source/Geometry/Analytic/imstkCylinder.h
@@ -36,9 +36,9 @@ public:
     ///
     /// \brief Constructor
     ///
-    explicit Cylinder(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double radius = 1.0, const double length = 1.0,
-                      const Vec3d& orientationAxis = Vec3d(0.0, 1.0, 0.0), const std::string& name = std::string("defaultCylinder")) :
-        AnalyticalGeometry(Type::Cylinder, name)
+    Cylinder(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double radius = 1.0, const double length = 1.0,
+             const Vec3d& orientationAxis = Vec3d(0.0, 1.0, 0.0), const std::string& name = std::string("defaultCylinder")) :
+        AnalyticalGeometry(name)
     {
         setPosition(pos);
         setOrientationAxis(orientationAxis);
@@ -47,7 +47,12 @@ public:
         updatePostTransformData();
     }
 
-    ~Cylinder() override = default;
+    virtual ~Cylinder() override = default;
+
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "Cylinder"; }
 
 public:
     ///
diff --git a/Source/Geometry/Analytic/imstkPlane.h b/Source/Geometry/Analytic/imstkPlane.h
index 74251f0706308ecf14d11c41f61f1e8bec14b5ec..129318900eb48c182fd5513e4031fd822e492e47 100644
--- a/Source/Geometry/Analytic/imstkPlane.h
+++ b/Source/Geometry/Analytic/imstkPlane.h
@@ -36,16 +36,24 @@ public:
     ///
     /// \brief Constructor
     ///
-    explicit Plane(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const Vec3d& normal = Vec3d(0.0, 1.0, 0.0),
-                   const std::string& name = std::string("defaultPlane")) :
-        AnalyticalGeometry(Type::Plane, name)
+    Plane(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const Vec3d& normal = Vec3d(0.0, 1.0, 0.0),
+          const std::string& name = std::string("defaultPlane")) :
+        AnalyticalGeometry(name)
     {
         setPosition(pos);
         setNormal(normal.normalized());
         updatePostTransformData();
     }
 
-    ~Plane() override = default;
+    ///
+    /// \brief Deconstructor
+    ///
+    virtual ~Plane() override = default;
+
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "Plane"; }
 
 public:
     ///
diff --git a/Source/Geometry/Analytic/imstkSphere.h b/Source/Geometry/Analytic/imstkSphere.h
index cef8ac02438834071d081aa8f5d561b08ad06207..a39a113e4661ca99faf597bc1ae99c435b7f7231 100644
--- a/Source/Geometry/Analytic/imstkSphere.h
+++ b/Source/Geometry/Analytic/imstkSphere.h
@@ -36,14 +36,19 @@ public:
     ///
     /// \brief Constructor
     ///
-    explicit Sphere(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double radius = 1.0, const std::string& name = std::string("defaultSphere")) :
-        AnalyticalGeometry(Type::Sphere, name)
+    Sphere(const Vec3d& pos = Vec3d(0.0, 0.0, 0.0), const double radius = 1.0, const std::string& name = std::string("defaultSphere")) :
+        AnalyticalGeometry(name)
     {
         setPosition(pos);
         setRadius(radius);
     }
 
-    ~Sphere() override = default;
+    virtual ~Sphere() override = default;
+
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "Sphere"; }
 
 public:
     ///
diff --git a/Source/Geometry/Decal/imstkDecal.cpp b/Source/Geometry/Decal/imstkDecal.cpp
index b8b4379fb106851e952308157a3945e9496295b2..cf402bce70964db02669bf2a7cefaa9301fd1460 100644
--- a/Source/Geometry/Decal/imstkDecal.cpp
+++ b/Source/Geometry/Decal/imstkDecal.cpp
@@ -24,7 +24,7 @@
 
 namespace imstk
 {
-Decal::Decal(const std::string& name) : AnalyticalGeometry(Geometry::Type::Decal, name),
+Decal::Decal(const std::string& name) : AnalyticalGeometry(name),
     m_dimensions(Vec3d(1.0, 1.0, 1.0))
 {
 }
diff --git a/Source/Geometry/Decal/imstkDecal.h b/Source/Geometry/Decal/imstkDecal.h
index 91c7d1ef1c16386d9720bb1d87e5a5160eb963ee..8761ec64569d9ecdd7944db0d04d7017595b43e4 100644
--- a/Source/Geometry/Decal/imstkDecal.h
+++ b/Source/Geometry/Decal/imstkDecal.h
@@ -30,6 +30,14 @@ class Decal : public AnalyticalGeometry
 public:
     Decal(const std::string& name = std::string(""));
 
+    virtual ~Decal() override = default;
+
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "Decal"; }
+
+public:
     ///
     /// \brief Print the cube info
     ///
@@ -50,7 +58,6 @@ protected:
 
     // Hide these functions
     using AnalyticalGeometry::getFunctionValue;
-    //using AnalyticalGeometry::getFunctionGrad;
 
     void applyTransform(const Mat4d& m) override;
 
diff --git a/Source/Geometry/Decal/imstkDecalPool.cpp b/Source/Geometry/Decal/imstkDecalPool.cpp
index 2b50adadf5d005e3a6e0c4f3fc000fa4b6ac6bdf..dba7629e9aebcc394ee972cf9e2acb6ec4622316 100644
--- a/Source/Geometry/Decal/imstkDecalPool.cpp
+++ b/Source/Geometry/Decal/imstkDecalPool.cpp
@@ -26,7 +26,7 @@
 namespace imstk
 {
 DecalPool::DecalPool(unsigned int maxNumDecals /*= 128*/, const std::string& name)
-    : Geometry(Geometry::Type::DecalPool, name)
+    : Geometry(name)
 {
     if (maxNumDecals <= 128)
     {
diff --git a/Source/Geometry/Decal/imstkDecalPool.h b/Source/Geometry/Decal/imstkDecalPool.h
index af589641b5a983859c0ab04cac3aac1b083a99f5..1d3f12d8af91883f558a70881a188dab405b8bb5 100644
--- a/Source/Geometry/Decal/imstkDecalPool.h
+++ b/Source/Geometry/Decal/imstkDecalPool.h
@@ -36,8 +36,22 @@ class Decal;
 class DecalPool : public Geometry
 {
 public:
+    ///
+    /// \brief Constructor
+    ///
     DecalPool(unsigned int maxNumDecals = 128, const std::string& name = std::string(""));
 
+    ///
+    /// \brief Deconstructor
+    ///
+    virtual ~DecalPool() override = default;
+
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "DecalPool"; }
+
+public:
     ///
     /// \brief Add a \ref Decal object to this pool
     ///
diff --git a/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.h b/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.h
index 7ebd9cc43fa16ad71e5788c8d75cdf8296ef9753..6dd2b3362094dfb9bfc0ba9b1cefb9ca0c7fe082 100644
--- a/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.h
+++ b/Source/Geometry/Implicit/imstkCompositeImplicitGeometry.h
@@ -44,15 +44,32 @@ public:
     using GeometryBoolPair = std::pair<std::shared_ptr<ImplicitGeometry>, GeometryBoolType>;
 
 public:
-    CompositeImplicitGeometry(std::string name    = "") : ImplicitGeometry(Type::CompositeImplicitGeometry, name) { }
+    ///
+    /// \brief Constructor
+    ///
+    CompositeImplicitGeometry(std::string name = "") : ImplicitGeometry(name) { }
+
+    ///
+    /// \brief Deconstructor
+    ///
     virtual ~CompositeImplicitGeometry() override = default;
 
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "CompositeImplicitGeometry"; }
+
 public:
     ///
     /// \brief Returns signed distance to surface at pos
     ///
     virtual double getFunctionValue(const Vec3d& pos) const override;
 
+    ///
+    /// \brief Add an implicit geometry to have boolean operations done with
+    /// \param geometry to use
+    /// \param boolean function type to use
+    ///
     void addImplicitGeometry(std::shared_ptr<ImplicitGeometry> geometry, const GeometryBoolType type) { geometries.push_back(GeometryBoolPair(geometry, type)); }
 
 protected:
diff --git a/Source/Geometry/Implicit/imstkImplicitGeometry.h b/Source/Geometry/Implicit/imstkImplicitGeometry.h
index 808edc58932fa149274a3bd2fc2fc3f173ea685c..a1fee16d362a0de95ba3f845c79bfe2bbb84bbd2 100644
--- a/Source/Geometry/Implicit/imstkImplicitGeometry.h
+++ b/Source/Geometry/Implicit/imstkImplicitGeometry.h
@@ -37,7 +37,7 @@ public:
     virtual ~ImplicitGeometry() override = default;
 
 protected:
-    ImplicitGeometry(Type geomType, std::string name = "") : Geometry(geomType, name) { }
+    ImplicitGeometry(std::string name = "") : Geometry(name) { }
 
 public:
     ///
diff --git a/Source/Geometry/Implicit/imstkSignedDistanceField.cpp b/Source/Geometry/Implicit/imstkSignedDistanceField.cpp
index c229d28d64522ad1e3dd3f918ca9891375f74baf..15da73db818bda36ae2eb76bfe7fe3fcb8872f42 100644
--- a/Source/Geometry/Implicit/imstkSignedDistanceField.cpp
+++ b/Source/Geometry/Implicit/imstkSignedDistanceField.cpp
@@ -81,7 +81,7 @@ trilinearSample(const Vec3d& structuredPt, T* imgPtr, const Vec3i& dim, const in
 }
 
 SignedDistanceField::SignedDistanceField(std::shared_ptr<ImageData> imageData, std::string name) :
-    ImplicitGeometry(Type::SignedDistanceField, name),
+    ImplicitGeometry(name),
     m_imageDataSdf(imageData), m_scale(1.0)
 {
     m_invSpacing = m_imageDataSdf->getInvSpacing();
diff --git a/Source/Geometry/Implicit/imstkSignedDistanceField.h b/Source/Geometry/Implicit/imstkSignedDistanceField.h
index a32ac03cf3fe982aeb9bd38aa5c1327030e4a696..1c05fe5f2bde9842b49e58c987909a2442815671 100644
--- a/Source/Geometry/Implicit/imstkSignedDistanceField.h
+++ b/Source/Geometry/Implicit/imstkSignedDistanceField.h
@@ -40,11 +40,22 @@ class SignedDistanceField : public ImplicitGeometry
 {
 public:
     ///
-    /// \brief Initialize with an image data SDF
+    /// \brief Constructor
+    /// \param ImageData to utilize
+    /// \param geometry name
     ///
     SignedDistanceField(std::shared_ptr<ImageData> imageData, std::string name = "");
+
+    ///
+    /// \brief Deconstructor
+    ///
     virtual ~SignedDistanceField() override = default;
 
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "SignedDistanceField"; }
+
 public:
     ///
     /// \brief Returns signed distance to surface at pos, returns clamped/nearest if out of bounds
diff --git a/Source/Geometry/Mesh/imstkHexahedralMesh.cpp b/Source/Geometry/Mesh/imstkHexahedralMesh.cpp
index 996a2dee4a439a97a76c38f90f35a5d5da2ada89..bfd5ea366619202076e306400083039482509e1f 100644
--- a/Source/Geometry/Mesh/imstkHexahedralMesh.cpp
+++ b/Source/Geometry/Mesh/imstkHexahedralMesh.cpp
@@ -26,7 +26,7 @@
 
 namespace imstk
 {
-HexahedralMesh::HexahedralMesh(const std::string& name) : VolumetricMesh(Geometry::Type::HexahedralMesh, name),
+HexahedralMesh::HexahedralMesh(const std::string& name) : VolumetricMesh(name),
     m_hexahedraIndices(std::make_shared<VecDataArray<int, 8>>())
 {
 }
diff --git a/Source/Geometry/Mesh/imstkHexahedralMesh.h b/Source/Geometry/Mesh/imstkHexahedralMesh.h
index 62f97108adae7b2fee7e675f83351338599deb89..3c0c091ac7df9c6b3eca9d71b6b1acf66ed8900b 100644
--- a/Source/Geometry/Mesh/imstkHexahedralMesh.h
+++ b/Source/Geometry/Mesh/imstkHexahedralMesh.h
@@ -38,6 +38,16 @@ public:
     ///
     HexahedralMesh(const std::string& name = std::string(""));
 
+    ///
+    /// \brief Deconstructor
+    ///
+    virtual ~HexahedralMesh() override = default;
+
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "HexahedralMesh"; }
+
 public:
     ///
     /// \brief Initializes the rest of the data structures given vertex positions and
@@ -66,6 +76,11 @@ public:
     /// \brief Extract surface Mesh
     bool extractSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh);
 
+    ///
+    /// \brief Returns true if the geometry is a mesh, else returns false
+    ///
+    bool isMesh() const override { return true; }
+
 // Accessors
 public:
     ///
diff --git a/Source/Geometry/Mesh/imstkImageData.cpp b/Source/Geometry/Mesh/imstkImageData.cpp
index 14ab6d725d26712ef02c85c5a159626a5db679bb..91e35b1ee5f451871c7063a0c17d568e0538b7f5 100644
--- a/Source/Geometry/Mesh/imstkImageData.cpp
+++ b/Source/Geometry/Mesh/imstkImageData.cpp
@@ -56,7 +56,7 @@ castImage(std::shared_ptr<AbstractDataArray> fromScalars, std::shared_ptr<ImageD
 }
 
 ImageData::ImageData(const std::string& name)
-    : PointSet(Geometry::Type::ImageData, name),
+    : PointSet(name),
     m_scalarArray(nullptr)
 {
 }
diff --git a/Source/Geometry/Mesh/imstkImageData.h b/Source/Geometry/Mesh/imstkImageData.h
index ab6b52054466562f7e2e515a7ae9d9a019587a60..9073907b8e4f83922a56b5170ebf3a6e7b5d5663 100644
--- a/Source/Geometry/Mesh/imstkImageData.h
+++ b/Source/Geometry/Mesh/imstkImageData.h
@@ -46,6 +46,11 @@ public:
     ///
     virtual ~ImageData() override = default;
 
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "ImageData"; }
+
 public:
     ///
     /// \brief Print the image data info
diff --git a/Source/Geometry/Mesh/imstkLineMesh.cpp b/Source/Geometry/Mesh/imstkLineMesh.cpp
index 7bc53ddc7bf7d635210ba2061e580d7e8827128e..0cb29668c2f29a51864676a9ddcc7bcae05ea418 100644
--- a/Source/Geometry/Mesh/imstkLineMesh.cpp
+++ b/Source/Geometry/Mesh/imstkLineMesh.cpp
@@ -25,7 +25,7 @@
 
 namespace imstk
 {
-LineMesh::LineMesh(const std::string& name) : PointSet(Type::LineMesh, name),
+LineMesh::LineMesh(const std::string& name) : PointSet(name),
     m_segmentIndices(std::make_shared<VecDataArray<int, 2>>())
 {
 }
diff --git a/Source/Geometry/Mesh/imstkLineMesh.h b/Source/Geometry/Mesh/imstkLineMesh.h
index 476c775e3d74771fdd0566f9444f5ead44afebd4..f1be32b32742543c3c1f3c0d5d2dddcc32c12205 100644
--- a/Source/Geometry/Mesh/imstkLineMesh.h
+++ b/Source/Geometry/Mesh/imstkLineMesh.h
@@ -42,6 +42,16 @@ public:
     ///
     LineMesh(const std::string& name = std::string(""));
 
+    ///
+    /// \brief Deconstructor
+    ///
+    virtual ~LineMesh() override = default;
+
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "LineMesh"; }
+
 public:
     ///
     /// \brief Initializes the rest of the data structures given vertex positions and
@@ -59,6 +69,12 @@ public:
     ///
     void print() const override;
 
+    ///
+    /// \brief Returns true if the geometry is a mesh, else returns false
+    ///
+    bool isMesh() const override { return true; }
+
+// Accessors
 public:
     ///
     /// \brief Get the number of segments/cells
diff --git a/Source/Geometry/Mesh/imstkPointSet.cpp b/Source/Geometry/Mesh/imstkPointSet.cpp
index 0348edce0a3da287c4b22d8a1a28f8505002f19a..f7e4e18d8c48ee88ceadebd3d7d39ebf509150b1 100644
--- a/Source/Geometry/Mesh/imstkPointSet.cpp
+++ b/Source/Geometry/Mesh/imstkPointSet.cpp
@@ -26,7 +26,7 @@
 
 namespace imstk
 {
-PointSet::PointSet(const Type type, const std::string& name) : Geometry(type, name),
+PointSet::PointSet(const std::string& name) : Geometry(name),
     m_initialVertexPositions(std::make_shared<VecDataArray<double, 3>>()),
     m_vertexPositions(std::make_shared<VecDataArray<double, 3>>())
 {
diff --git a/Source/Geometry/Mesh/imstkPointSet.h b/Source/Geometry/Mesh/imstkPointSet.h
index 1da414fb7f04d9775f0a07dc35c84ef579dacfbd..96fa1f97c8f9b32f982ece6fd592b3f450980b10 100644
--- a/Source/Geometry/Mesh/imstkPointSet.h
+++ b/Source/Geometry/Mesh/imstkPointSet.h
@@ -39,8 +39,22 @@ template<typename T, int N> class VecDataArray;
 class PointSet : public Geometry
 {
 public:
-    PointSet(const Type type = Geometry::Type::PointSet, const std::string& name = std::string(""));
+    ///
+    /// \brief Constructor
+    ///
+    PointSet(const std::string& name = std::string(""));
+
+    ///
+    /// \brief Deconstructor
+    ///
+    virtual ~PointSet() override = default;
 
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "PointSet"; }
+
+public:
     ///
     /// \brief Initializes the data structure given vertex positions
     ///
@@ -61,8 +75,8 @@ public:
     ///
     virtual void computeBoundingBox(Vec3d& lowerCorner, Vec3d& upperCorner, const double paddingPercent = 0.0) override;
 
-    // Accessors
-
+// Accessors
+public:
     ///
     /// \brief Sets initial positions from an array
     ///
@@ -116,6 +130,7 @@ public:
     ///
     size_t getMaxNumVertices() const { return m_maxNumVertices; }
 
+// Attributes
 public:
     ///
     /// \brief Set a data array holding some per vertex data
diff --git a/Source/Geometry/Mesh/imstkSurfaceMesh.cpp b/Source/Geometry/Mesh/imstkSurfaceMesh.cpp
index e893195ef1ad81d0968adefd354d78b019614a42..37fd5affa7f46dd269f3989c3c11bc8a27dc220e 100644
--- a/Source/Geometry/Mesh/imstkSurfaceMesh.cpp
+++ b/Source/Geometry/Mesh/imstkSurfaceMesh.cpp
@@ -26,7 +26,7 @@
 
 namespace imstk
 {
-SurfaceMesh::SurfaceMesh(const std::string& name) : PointSet(Type::SurfaceMesh, name),
+SurfaceMesh::SurfaceMesh(const std::string& name) : PointSet(name),
     m_triangleIndices(std::make_shared<VecDataArray<int, 3>>())
 {
 }
@@ -658,7 +658,6 @@ SurfaceMesh::deepCopy(std::shared_ptr<SurfaceMesh> srcMesh)
     this->m_originalNumVertices = srcMesh->m_originalNumVertices;
 
     // Geometry members
-    this->m_type = srcMesh->m_type;
     this->m_name = srcMesh->m_name;
     this->m_geometryIndex    = getUniqueID();
     this->m_transformApplied = srcMesh->m_transformApplied;
diff --git a/Source/Geometry/Mesh/imstkSurfaceMesh.h b/Source/Geometry/Mesh/imstkSurfaceMesh.h
index cfde7badecc5584c4bd02c45d97764e7a114e228..bd51b227697a6aa4d159a05546bc002072e72cab 100644
--- a/Source/Geometry/Mesh/imstkSurfaceMesh.h
+++ b/Source/Geometry/Mesh/imstkSurfaceMesh.h
@@ -82,6 +82,17 @@ public:
     ///
     SurfaceMesh(const std::string& name = std::string(""));
 
+    ///
+    /// \brief Deconstructor
+    ///
+    virtual ~SurfaceMesh() override = default;
+
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "SurfaceMesh"; }
+
+public:
     ///
     /// \brief Initializes the rest of the data structures given vertex positions and
     ///  triangle connectivity
@@ -168,6 +179,11 @@ public:
     ///
     void deepCopy(std::shared_ptr<SurfaceMesh> srcMesh);
 
+    ///
+    /// \brief Returns true if the geometry is a mesh, else returns false
+    ///
+    bool isMesh() const override { return true; }
+
 // Accessors
 public:
     ///
diff --git a/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp b/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp
index 29f76cf0b3ca5663980204e924e7e641e0a58484..08677ed5a4dc3fc3fca59fc821759822565439c1 100644
--- a/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp
+++ b/Source/Geometry/Mesh/imstkTetrahedralMesh.cpp
@@ -26,7 +26,7 @@
 
 namespace imstk
 {
-TetrahedralMesh::TetrahedralMesh(const std::string& name) : VolumetricMesh(Geometry::Type::TetrahedralMesh, name),
+TetrahedralMesh::TetrahedralMesh(const std::string& name) : VolumetricMesh(name),
     m_tetrahedraIndices(std::make_shared<VecDataArray<int, 4>>())
 {
 }
diff --git a/Source/Geometry/Mesh/imstkTetrahedralMesh.h b/Source/Geometry/Mesh/imstkTetrahedralMesh.h
index 0d3b7cfe89c0ca25554e0115da38aa2852561964..c21c0ec398d30a03d9a727a4aecf2dc3a7970119 100644
--- a/Source/Geometry/Mesh/imstkTetrahedralMesh.h
+++ b/Source/Geometry/Mesh/imstkTetrahedralMesh.h
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "imstkVolumetricMesh.h"
+
 #include <array>
 
 namespace imstk
@@ -44,6 +45,17 @@ public:
     ///
     TetrahedralMesh(const std::string& name = std::string(""));
 
+    ///
+    /// \brief Deconstructor
+    ///
+    virtual ~TetrahedralMesh() override = default;
+
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "TetrahedralMesh"; }
+
+public:
     ///
     /// \brief Initializes the rest of the data structures given vertex positions and
     ///  tetrahedra connectivity
@@ -86,6 +98,11 @@ public:
     ///
     void computeTetrahedronBoundingBox(const size_t& tetId, Vec3d& min, Vec3d& max) const;
 
+    ///
+    /// \brief Returns true if the geometry is a mesh, else returns false
+    ///
+    bool isMesh() const override { return true; }
+
 // Accessors
 public:
     ///
diff --git a/Source/Geometry/Mesh/imstkVolumetricMesh.h b/Source/Geometry/Mesh/imstkVolumetricMesh.h
index c3b329fab62e010d0cbc15a51a078cc0c2e43d84..4b9deb669851ae1f070b2154f6ff6bc60dad3445 100644
--- a/Source/Geometry/Mesh/imstkVolumetricMesh.h
+++ b/Source/Geometry/Mesh/imstkVolumetricMesh.h
@@ -22,11 +22,11 @@
 #pragma once
 
 #include "imstkPointSet.h"
-#include <memory>
 
 namespace imstk
 {
 class SurfaceMesh;
+
 ///
 /// \class VolumetricMesh
 ///
@@ -35,7 +35,12 @@ class SurfaceMesh;
 class VolumetricMesh : public PointSet
 {
 public:
+    ///
+    /// \brief Deconstructor
+    ///
+    virtual ~VolumetricMesh() override = default;
 
+public:
     ///
     /// \brief Computes the attached surface mesh
     ///
@@ -52,7 +57,7 @@ public:
     void setAttachedSurfaceMesh(std::shared_ptr<SurfaceMesh> surfaceMesh);
 
 protected:
-    VolumetricMesh(Geometry::Type type, const std::string& name = std::string("")) : PointSet(type, name) {}
+    VolumetricMesh(const std::string& name = std::string("")) : PointSet(name) {}
 
     std::shared_ptr<SurfaceMesh> m_attachedSurfaceMesh;          ///> Attached surface mesh
 };
diff --git a/Source/Geometry/Particles/imstkRenderParticles.cpp b/Source/Geometry/Particles/imstkRenderParticles.cpp
index d2d71da271f227c516db419757d7ea49dbde1c2a..b2f298b57c9e7b59f71ac0a0ecfc33b8dcc3e120 100644
--- a/Source/Geometry/Particles/imstkRenderParticles.cpp
+++ b/Source/Geometry/Particles/imstkRenderParticles.cpp
@@ -25,7 +25,7 @@
 namespace imstk
 {
 RenderParticles::RenderParticles(const unsigned int maxNumParticles /*=128*/, const std::string& name /*= std::string("")*/)
-    : Geometry(Geometry::Type::RenderParticles, name)
+    : Geometry(name)
 {
     if (maxNumParticles <= 128)
     {
diff --git a/Source/Geometry/Particles/imstkRenderParticles.h b/Source/Geometry/Particles/imstkRenderParticles.h
index b36415f843278a163b4df2b5bea354559f18d75a..9a2cc397c18e9c3b68882317191966ceb2e6fed4 100644
--- a/Source/Geometry/Particles/imstkRenderParticles.h
+++ b/Source/Geometry/Particles/imstkRenderParticles.h
@@ -62,7 +62,6 @@ struct RenderParticle
 class RenderParticles : public Geometry
 {
 public:
-
     ///
     /// \brief Constructor
     /// \param maxNumParticles Number of particles this emitter can produce
@@ -71,6 +70,14 @@ public:
     ///
     RenderParticles(const unsigned int maxNumParticles = 128, const std::string& name = std::string(""));
 
+    virtual ~RenderParticles() override = default;
+
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const override { return "RenderParticles"; }
+
+public:
     ///
     /// \brief Set size of particle
     /// \param size Particle size, this determines how much each keyframe
diff --git a/Source/Geometry/imstkGeometry.cpp b/Source/Geometry/imstkGeometry.cpp
index c9459724ee3a30ae98847ca97c1568a3f69fe762..72a404455aebf993db6bc8819db0a564fb17205d 100644
--- a/Source/Geometry/imstkGeometry.cpp
+++ b/Source/Geometry/imstkGeometry.cpp
@@ -25,20 +25,20 @@
 
 namespace imstk
 {
-Geometry::Geometry(const Geometry::Type type, const std::string& name) :
-    m_type(type), m_name(name), m_geometryIndex(Geometry::getUniqueID()), m_transform(Mat4d::Identity())
+Geometry::Geometry(const std::string& name) :
+    m_name(name), m_geometryIndex(Geometry::getUniqueID()), m_transform(Mat4d::Identity())
 {
     // If the geometry name is empty, enumerate it by name (which will not be duplicated)
     if (m_name.empty())
     {
-        m_name = getTypeName() + std::string("-") + std::to_string(m_geometryIndex);
+        m_name = std::string("unnamed_geometry-") + std::to_string(m_geometryIndex);
     }
 }
 
 void
 Geometry::print() const
 {
-    LOG(INFO) << this->getTypeName();
+    LOG(INFO) << getTypeName();
     LOG(INFO) << "Transform: " << m_transform;
 }
 
@@ -215,45 +215,6 @@ Geometry::getScaling() const
         m_transform.block<3, 1>(0, 2).norm());
 }
 
-const std::string
-Geometry::getTypeName() const
-{
-    // /todo: create an actual object factory
-    switch (m_type)
-    {
-    case Type::Plane: return "Plane";
-    case Type::Sphere: return "Sphere";
-    case Type::Cylinder: return "Cylinder";
-    case Type::Cube: return "Cube";
-    case Type::Capsule: return "Capsule";
-    case Type::PointSet: return "PointSet";
-    case Type::SurfaceMesh: return "SurfaceMesh";
-    case Type::TetrahedralMesh: return "TetrahedralMesh";
-    case Type::HexahedralMesh: return "HexahedralMesh";
-    case Type::LineMesh: return "LineMesh";
-    case Type::Decal: return "Decal";
-    case Type::DecalPool: return "DecalPool";
-    case Type::RenderParticles: return "RenderParticles";
-    case Type::ImageData: return "ImageData";
-    case Type::SignedDistanceField: return "SignedDistanceField";
-    case Type::CompositeImplicitGeometry: return "CompositeImplicitGeometry";
-    default:
-        LOG(FATAL) << "Mesh type to string has not been completely implemented";
-        return "";
-    }
-}
-
-bool
-Geometry::isMesh() const
-{
-    return (this->m_type == Type::HexahedralMesh
-            || this->m_type == Type::SurfaceMesh
-            || this->m_type == Type::TetrahedralMesh
-            || this->m_type == Type::LineMesh
-            || this->m_type == Type::PointSet
-            ) ? true : false;
-}
-
 // Static mutex lock
 ParallelUtils::SpinLock
 Geometry::s_GeomGlobalLock;
diff --git a/Source/Geometry/imstkGeometry.h b/Source/Geometry/imstkGeometry.h
index 6362525b0be34c56324fafc18050fd4e106d4604..340857b21666d6f2ebf536bc621318f79e92002b 100644
--- a/Source/Geometry/imstkGeometry.h
+++ b/Source/Geometry/imstkGeometry.h
@@ -25,8 +25,6 @@
 #include "imstkMacros.h"
 #include "imstkMath.h"
 
-#include <tbb/concurrent_unordered_set.h>
-
 #include <unordered_map>
 #include <string>
 
@@ -44,30 +42,6 @@ class SpinLock;
 class Geometry : public EventObject
 {
 public:
-    ///
-    /// \brief Enumeration for the geometry type
-    ///
-    enum class Type
-    {
-        Plane,
-        Sphere,
-        Cylinder,
-        Cube,
-        Capsule,
-        PointSet,
-        SurfaceMesh,
-        TetrahedralMesh,
-        HexahedralMesh,
-        LineMesh,
-        Decal,
-        DecalPool,
-        RenderParticles,
-        ImageData,
-        SignedDistanceField,
-        CompositeImplicitGeometry,
-        MultiBlockGeometry
-    };
-
     ///
     /// \brief Enumeration for the transformation to apply
     /// \params ApplyToTransform to apply the transformation to the data
@@ -90,16 +64,23 @@ public:
         PostTransform
     };
 
+protected:
     ///
     /// \brief Constructor
     ///
-    explicit Geometry(const Geometry::Type type, const std::string& name = std::string(""));
+    Geometry(const std::string& name = std::string(""));
 
+public:
     ///
     /// \brief Destructor
     ///
     virtual ~Geometry() override = default;
 
+    ///
+    /// \brief Returns the string representing the type name of the geometry
+    ///
+    virtual const std::string getTypeName() const = 0;
+
 public:
     SIGNAL(Geometry,modified);
 
@@ -186,26 +167,11 @@ public:
         m_transformApplied = false;
     }
 
-    ///
-    /// \brief Returns the type of the geometry
-    ///
-    Type getType() const{ return m_type; }
-
     ///
     /// \brief Get name of the geometry
     ///
     const std::string& getName() const{ return m_name; }
 
-    ///
-    /// \brief Returns the string representing the type name of the geometry
-    ///
-    const std::string getTypeName() const;
-
-    ///
-    /// \brief Returns true if the geometry is a mesh, else returns false
-    ///
-    bool isMesh() const;
-
     ///
     /// \brief Get the global (unique) index of the geometry
     ///
@@ -216,6 +182,11 @@ public:
     ///
     static uint32_t getTotalNumberGeometries() { return s_NumGeneratedGegometries; }
 
+    ///
+    /// \brief Returns true if the geometry is a mesh, else returns false
+    ///
+    virtual bool isMesh() const{ return false; }
+
     ///
     /// \brief Post modified event
     ///
@@ -248,7 +219,6 @@ protected:
     ///
     virtual void applyTransform(const Mat4d& imstkNotUsed(m)) { }
 
-    Type m_type;                            ///> Type of geometry
     std::string m_name;                     ///> Unique name for each geometry
     uint32_t    m_geometryIndex;            ///> Unique ID assigned to each geometry upon construction
 
diff --git a/Source/GeometryMappers/imstkTetraTriangleMap.cpp b/Source/GeometryMappers/imstkTetraTriangleMap.cpp
index 9f82c5e08b5df767556cbdbe3e80d5298a33bf3b..1ce018cfb802e75fc8f502c9a4a7f6cb2b77a55f 100644
--- a/Source/GeometryMappers/imstkTetraTriangleMap.cpp
+++ b/Source/GeometryMappers/imstkTetraTriangleMap.cpp
@@ -168,7 +168,7 @@ TetraTriangleMap::isValid() const
 void
 TetraTriangleMap::setMaster(std::shared_ptr<Geometry> master)
 {
-    CHECK(master->getType() == Geometry::Type::TetrahedralMesh) <<
+    CHECK(std::dynamic_pointer_cast<TetrahedralMesh>(master) != nullptr) <<
         "The geometry provided as master is not of tetrahedral type";
 
     GeometryMap::setMaster(master);
@@ -177,7 +177,7 @@ TetraTriangleMap::setMaster(std::shared_ptr<Geometry> master)
 void
 TetraTriangleMap::setSlave(std::shared_ptr<Geometry> slave)
 {
-    CHECK(slave->getType() == Geometry::Type::SurfaceMesh) <<
+    CHECK(std::dynamic_pointer_cast<SurfaceMesh>(slave) != nullptr) <<
         "The geometry provided as slave is not of triangular type (surface)";
 
     GeometryMap::setSlave(slave);
diff --git a/Source/MeshIO/imstkVegaMeshIO.cpp b/Source/MeshIO/imstkVegaMeshIO.cpp
index 6bf348161fcb049688ad978889fe4e7c399fa5a1..b2def6c513f560c51fa7b4719967b26a6b264b66 100644
--- a/Source/MeshIO/imstkVegaMeshIO.cpp
+++ b/Source/MeshIO/imstkVegaMeshIO.cpp
@@ -52,10 +52,9 @@ VegaMeshIO::write(const std::shared_ptr<imstk::PointSet> imstkMesh, const std::s
 
     CHECK(imstkVolMesh != nullptr) << "VegaMeshIO::write error: imstk::Mesh is not a volumetric mesh";
 
-    switch (imstkVolMesh->getType())
+    const std::string geometryType = imstkVolMesh->getTypeName();
+    if (geometryType == "TetrahedralMesh" || geometryType == "HexahedralMesh")
     {
-    case Geometry::Type::TetrahedralMesh:
-    case Geometry::Type::HexahedralMesh:
         auto vegaMesh = convertVolumetricMeshToVegaMesh(imstkVolMesh);
 
         CHECK(vegaMesh != nullptr) << "VegaMeshIO::write error: failed to convert volumetric mesh to vega mesh";
@@ -66,7 +65,6 @@ VegaMeshIO::write(const std::shared_ptr<imstk::PointSet> imstkMesh, const std::s
         CHECK(write_status == 0) << "VegaMeshIO::write error: failed to write .veg file";
 
         return true;
-        break;
     }
 
     LOG(WARNING) << "VegaMeshIO::write error: this element type not supported in vega";
@@ -151,7 +149,7 @@ std::shared_ptr<vega::VolumetricMesh>
 VegaMeshIO::convertVolumetricMeshToVegaMesh(const std::shared_ptr<imstk::VolumetricMesh> imstkVolMesh)
 {
     // as of now, only works for TET elements
-    if (imstkVolMesh->getType() == Geometry::Type::TetrahedralMesh)
+    if (imstkVolMesh->getTypeName() == "TetrahedralMesh")
     {
         // Using default material properties to append to the .veg file
         const double E       = 1E7;
diff --git a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp
index 59a39f7a48447929bf32d063951be79bee4d3afa..b8bb91de7bc5f2028894836d3502ff94b64a813a 100644
--- a/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp
+++ b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp
@@ -21,8 +21,8 @@
 
 #include "imstkVTKRenderDelegate.h"
 #include "imstkDebugRenderGeometry.h"
-#include "imstkGeometry.h"
 #include "imstkLogger.h"
+#include "imstkPointSet.h"
 #include "imstkVisualModel.h"
 #include "imstkVolumeRenderMaterial.h"
 
@@ -71,67 +71,62 @@ VTKRenderDelegate::VTKRenderDelegate(std::shared_ptr<VisualModel> visualModel) :
 std::shared_ptr<VTKRenderDelegate>
 VTKRenderDelegate::makeDelegate(std::shared_ptr<VisualModel> visualModel)
 {
-    if (visualModel->getGeometry()->isMesh())
+    const std::string geomType = visualModel->getGeometry()->getTypeName();
+
+    if (visualModel->getRenderMaterial()->getDisplayMode() == RenderMaterial::DisplayMode::Fluid)
     {
-        if (visualModel->getRenderMaterial()->getDisplayMode() == RenderMaterial::DisplayMode::Fluid)
+        if (std::dynamic_pointer_cast<PointSet>(visualModel->getGeometry()) != nullptr)
         {
             return std::make_shared<VTKFluidRenderDelegate>(visualModel);
         }
+    }
 
-        switch (visualModel->getGeometry()->getType())
-        {
-        case Geometry::Type::PointSet:
+    if (visualModel->getGeometry()->isMesh())
+    {
+        if (geomType == "PointSet")
         {
             return std::make_shared<VTKPointSetRenderDelegate>(visualModel);
         }
-        case Geometry::Type::SurfaceMesh:
+        else if (geomType == "SurfaceMesh")
         {
             return std::make_shared<VTKSurfaceMeshRenderDelegate>(visualModel);
         }
-        case Geometry::Type::TetrahedralMesh:
+        else if (geomType == "TetrahedralMesh")
         {
             return std::make_shared<VTKTetrahedralMeshRenderDelegate>(visualModel);
         }
-        case Geometry::Type::LineMesh:
+        else if (geomType == "LineMesh")
         {
             return std::make_shared<VTKLineMeshRenderDelegate>(visualModel);
         }
-        case Geometry::Type::HexahedralMesh:
+        else if (geomType == "HexahedralMesh")
         {
             return std::make_shared<VTKHexahedralMeshRenderDelegate>(visualModel);
         }
-        default:
-        {
-            LOG(FATAL) << "RenderDelegate::makeDelegate error: Mesh type incorrect.";
-            return nullptr;     // will never be reached
-        }
-        }
     }
     else
     {
-        switch (visualModel->getGeometry()->getType())
-        {
-        case Geometry::Type::Plane:
+        if (geomType == "Plane")
         {
             return std::make_shared<VTKPlaneRenderDelegate>(visualModel);
         }
-        case Geometry::Type::Sphere:
+        else if (geomType == "Sphere")
         {
             return std::make_shared<VTKSphereRenderDelegate>(visualModel);
         }
-        case Geometry::Type::Capsule:
+        else if (geomType == "Capsule")
         {
             return std::make_shared<VTKCapsuleRenderDelegate>(visualModel);
         }
-        case Geometry::Type::Cube:
+        else if (geomType == "Cube")
         {
             return std::make_shared<VTKCubeRenderDelegate>(visualModel);
         }
-        case Geometry::Type::Cylinder:
+        else if (geomType == "Cylinder")
         {
             return std::make_shared<VTKCylinderRenderDelegate>(visualModel);
         }
-        case Geometry::Type::ImageData:
+        else if (geomType == "ImageData")
         {
             if (visualModel->getRenderMaterial()->getDisplayMode() == RenderMaterial::DisplayMode::Points)
             {
@@ -142,13 +137,9 @@ VTKRenderDelegate::makeDelegate(std::shared_ptr<VisualModel> visualModel)
                 return std::make_shared<VTKImageDataRenderDelegate>(visualModel);
             }
         }
-        default:
-        {
-            LOG(FATAL) << "RenderDelegate::makeDelegate error: Geometry type incorrect.";
-            return nullptr;     // will never be reached
-        }
-        }
     }
+    LOG(FATAL) << "RenderDelegate::makeDelegate error: Geometry type incorrect.";
+    return nullptr;
 }
 
 std::shared_ptr<VTKRenderDelegate>
diff --git a/Source/apiUtilities/imstkAPIUtilities.cpp b/Source/apiUtilities/imstkAPIUtilities.cpp
index c3642136038b77c8231bb7e53adfdaa4cec8ecc2..95620bb43f7adfba8f78b60fcfddf009c928be46 100644
--- a/Source/apiUtilities/imstkAPIUtilities.cpp
+++ b/Source/apiUtilities/imstkAPIUtilities.cpp
@@ -44,11 +44,20 @@ namespace imstk
 {
 namespace apiutils
 {
+std::unordered_map<std::string, std::function<std::shared_ptr<Geometry>()>> geomMakeFunctions =
+{
+    { "Sphere", []() { return std::make_shared<Sphere>(); } },
+    { "Plane", []() { return std::make_shared<Sphere>(); } },
+    { "Cube", []() { return std::make_shared<Sphere>(); } },
+    { "Capsule", []() { return std::make_shared<Sphere>(); } },
+    { "Cylinder", []() { return std::make_shared<Sphere>(); } }
+};
+
 ///
 /// \brief Create a analytical visual scene object that and add it to the scene
 ///
 std::shared_ptr<SceneObject>
-createVisualAnalyticalSceneObject(Geometry::Type         type,
+createVisualAnalyticalSceneObject(std::string            type,
                                   std::shared_ptr<Scene> scene,
                                   const std::string&     objName,
                                   const Vec3d            scale /* = 1.*/,
@@ -57,33 +66,12 @@ createVisualAnalyticalSceneObject(Geometry::Type         type,
     CHECK(scene != nullptr) << "createVisualAnalyticalSceneObject: Scene is not valid!";
     CHECK(!objName.empty()) << "createVisualAnalyticalSceneObject: Name is empty!";
 
-    std::shared_ptr<Geometry> geom;
-    switch (type)
+    if (geomMakeFunctions.count(type) == 0)
     {
-    case Geometry::Type::Sphere:
-        geom = std::make_shared<Sphere>();
-        break;
-
-    case Geometry::Type::Plane:
-        geom = std::make_shared<Plane>();
-        break;
-
-    case Geometry::Type::Cube:
-        geom = std::make_shared<Cube>();
-        break;
-
-    case Geometry::Type::Capsule:
-        geom = std::make_shared<Capsule>();
-        break;
-
-    case Geometry::Type::ImageData:
-        geom = std::make_shared<ImageData>();
-        break;
-
-    default:
         LOG(WARNING) << "createVisualAnalyticalSceneObject: Scene object geometry type is not analytical!";
         return nullptr;
     }
+    std::shared_ptr<Geometry> geom = geomMakeFunctions[type]();
 
     geom->scale(scale, Geometry::TransformType::ApplyToData);
     geom->translate(t, Geometry::TransformType::ApplyToData);
@@ -99,7 +87,7 @@ createVisualAnalyticalSceneObject(Geometry::Type         type,
 /// \brief Create a analytical colliding scene object that and add it to the scene
 ///
 std::shared_ptr<CollidingObject>
-createCollidingAnalyticalSceneObject(Geometry::Type         type,
+createCollidingAnalyticalSceneObject(std::string            type,
                                      std::shared_ptr<Scene> scene,
                                      const std::string&     objName,
                                      const Vec3d            scale /*= 1.*/,
@@ -108,25 +96,12 @@ createCollidingAnalyticalSceneObject(Geometry::Type         type,
     CHECK(scene != nullptr) << "createCollidingSphereSceneObject: Scene is not valid!";
     CHECK(!objName.empty()) << "createCollidingAnalyticalSceneObject: Name is empty!";
 
-    std::shared_ptr<Geometry> geom;
-    switch (type)
+    if (geomMakeFunctions.count(type) == 0)
     {
-    case Geometry::Type::Sphere:
-        geom = std::make_shared<Sphere>();
-        break;
-
-    case Geometry::Type::Plane:
-        geom = std::make_shared<Plane>();
-        break;
-
-    case Geometry::Type::Cube:
-        geom = std::make_shared<Cube>();
-        break;
-
-    default:
         LOG(WARNING) << "createCollidingAnalyticalSceneObject: Scene object geometry type is not analytical!";
         return nullptr;
     }
+    std::shared_ptr<Geometry> geom = geomMakeFunctions[type]();
 
     geom->scale(scale, Geometry::TransformType::ApplyToData);
     geom->translate(t, Geometry::TransformType::ApplyToData);
diff --git a/Source/apiUtilities/imstkAPIUtilities.h b/Source/apiUtilities/imstkAPIUtilities.h
index 7608daddf2055230a42653e8201a31e2e6de1675..c0b9ed9b2cec01197f277406b57df33100eeb785 100644
--- a/Source/apiUtilities/imstkAPIUtilities.h
+++ b/Source/apiUtilities/imstkAPIUtilities.h
@@ -43,7 +43,7 @@ namespace apiutils
 ///
 /// \brief Create a analytical visual scene object that and add it to the scene
 ///
-std::shared_ptr<SceneObject> createVisualAnalyticalSceneObject(Geometry::Type type,
+std::shared_ptr<SceneObject> createVisualAnalyticalSceneObject(std::string type,
                                                                std::shared_ptr<Scene> scene,
                                                                const std::string& objName,
                                                                const Vec3d scale = Vec3d(1.0, 1.0, 1.0),
@@ -52,7 +52,7 @@ std::shared_ptr<SceneObject> createVisualAnalyticalSceneObject(Geometry::Type ty
 ///
 /// \brief Create a analytical colliding scene object that and add it to the scene
 ///
-std::shared_ptr<CollidingObject> createCollidingAnalyticalSceneObject(Geometry::Type type,
+std::shared_ptr<CollidingObject> createCollidingAnalyticalSceneObject(std::string type,
                                                                       std::shared_ptr<Scene> scene,
                                                                       const std::string& objName,
                                                                       const Vec3d scale = Vec3d(1.0, 1.0, 1.0),