diff --git a/GUI/Models/GUIDomainSampleVisitor.cpp b/GUI/Models/GUIDomainSampleVisitor.cpp
index c0a18d115ea8c44b3fd254df0c13766e0b73a402..6e881b9bbb308e3ac697f2e18ece223f8a27f5e5 100644
--- a/GUI/Models/GUIDomainSampleVisitor.cpp
+++ b/GUI/Models/GUIDomainSampleVisitor.cpp
@@ -45,13 +45,13 @@
 #include "Sample/SoftParticle/SoftParticles.h"
 
 #include <boost/polymorphic_cast.hpp>
-using boost::polymorphic_downcast;
+using boost::polymorphic_cast;
 
 namespace {
 template <typename T> T* AddFormFactorItem(SessionItem* parent)
 {
     if (parent->hasModelType<ParticleItem>())
-        return polymorphic_downcast<ParticleItem*>(parent)->setFormFactorType<T>();
+        return polymorphic_cast<ParticleItem*>(parent)->setFormFactorType<T>();
     else if (parent->modelType() == "MesoCrystal")
         return parent->setGroupPropertyType<T>(MesoCrystalItem::P_OUTER_SHAPE);
     else
@@ -130,7 +130,7 @@ void GUIDomainSampleVisitor::visit(const MultiLayer* sample)
 
 void GUIDomainSampleVisitor::visit(const Particle* sample)
 {
-    auto particle_item = polymorphic_downcast<ParticleItem*>
+    auto particle_item = polymorphic_cast<ParticleItem*>
         (InsertIParticle(sample, ParticleItem::M_TYPE));
     particle_item->setMaterial(createMaterialFromDomain(sample->material()));
 }
diff --git a/GUI/Models/ItemWithMaterial.cpp b/GUI/Models/ItemWithMaterial.cpp
index 7da9728b87dc2c68c6695d7919fd00f573c8b84d..b86b5d90121043bce9c909bcd69ac9b0f25f99a4 100644
--- a/GUI/Models/ItemWithMaterial.cpp
+++ b/GUI/Models/ItemWithMaterial.cpp
@@ -17,8 +17,6 @@
 
 const QString ItemWithMaterial::P_MATERIAL = "Material";
 
-ItemWithMaterial::~ItemWithMaterial() = default;
-
 ExternalProperty ItemWithMaterial::material() const
 {
     return getItemValue(P_MATERIAL).value<ExternalProperty>();
diff --git a/GUI/Models/ItemWithMaterial.h b/GUI/Models/ItemWithMaterial.h
index 4f8a4261888ec54c66d514c10fdc6ddd9b0b9222..1b17cf138eea3b626aca4aba97a006cd8f910503 100644
--- a/GUI/Models/ItemWithMaterial.h
+++ b/GUI/Models/ItemWithMaterial.h
@@ -18,13 +18,11 @@
 #include "GUI/Models/ExternalProperty.h"
 #include "GUI/Models/SessionGraphicsItem.h"
 
-class BA_CORE_API_ ItemWithMaterial : public SessionGraphicsItem {
+class BA_CORE_API_ ItemWithMaterial : public virtual SessionGraphicsItem {
 private:
     static const QString P_MATERIAL;
 
 public:
-    virtual ~ItemWithMaterial() = 0;
-
     ExternalProperty material() const;
     void setMaterial(const ExternalProperty& material);
     static bool isMaterialPropertyName(const QString& name);
diff --git a/GUI/Models/ItemWithParticles.cpp b/GUI/Models/ItemWithParticles.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cea0ad1133ca32a1fc2787fd0b862eda7179b7cb
--- /dev/null
+++ b/GUI/Models/ItemWithParticles.cpp
@@ -0,0 +1,55 @@
+//  ************************************************************************************************
+//
+//  BornAgain: simulate and fit reflection and scattering
+//
+//! @file      GUI/Models/ItemWithParticles.cpp
+//! @brief     Implements class ItemWithParticles
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+//  ************************************************************************************************
+
+#include "GUI/Models/ItemWithParticles.h"
+#include "GUI/Models/VectorItem.h"
+#include "GUI/Models/SessionItemUtils.h"
+
+const QString ItemWithParticles::P_ABUNDANCE = "Abundance";
+const QString ItemWithParticles::P_POSITION = "Position Offset";
+const QString ItemWithParticles::T_TRANSFORMATION = "Transformation Tag";
+
+ItemWithParticles::ItemWithParticles(const QString& model_type, const QString& abundance_tooltip,
+                                     const QString& position_tooltip)
+    : SessionGraphicsItem(model_type)
+{
+    addProperty(P_ABUNDANCE, 1.0)
+        ->setLimits(RealLimits::limited(0.0, 1.0))
+        .setDecimals(3)
+        .setToolTip(abundance_tooltip);
+    addProperty<VectorItem>(P_POSITION)->setToolTip(position_tooltip);
+
+    registerTag(T_TRANSFORMATION, 0, 1, QStringList() << "Rotation");
+
+    mapper()->setOnParentChange([this](SessionItem* parent) {
+        if (GUI::Session::ItemUtils::HasOwnAbundance(parent)) {
+            setItemValue(P_ABUNDANCE, 1.0);
+            getItem(P_ABUNDANCE)->setEnabled(false);
+            if (isShellParticle()) {
+                auto pos = item<VectorItem>(P_POSITION);
+                pos->setVector(kvector_t());
+                pos->setEnabled(false);
+            }
+        } else {
+            getItem(P_ABUNDANCE)->setEnabled(true);
+            if (isShellParticle()) 
+                item<VectorItem>(P_POSITION)->setEnabled(true);
+        }
+    });
+}
+
+bool ItemWithParticles::isShellParticle() const
+{
+    return false;
+}
diff --git a/GUI/Models/ItemWithParticles.h b/GUI/Models/ItemWithParticles.h
new file mode 100644
index 0000000000000000000000000000000000000000..51de33901e8163b1b0573c847467ad4782772124
--- /dev/null
+++ b/GUI/Models/ItemWithParticles.h
@@ -0,0 +1,35 @@
+//  ************************************************************************************************
+//
+//  BornAgain: simulate and fit reflection and scattering
+//
+//! @file      GUI/Models/ItemWithParticles.h
+//! @brief     Defines abstract item with a material property
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+//  ************************************************************************************************
+
+#ifndef BORNAGAIN_GUI_MODELS_ITEMWITHPARTICLES_H
+#define BORNAGAIN_GUI_MODELS_ITEMWITHPARTICLES_H
+
+#include "GUI/Models/ExternalProperty.h"
+#include "GUI/Models/SessionGraphicsItem.h"
+
+class BA_CORE_API_ ItemWithParticles : public virtual SessionGraphicsItem {
+public:
+    static const QString P_ABUNDANCE;
+    static const QString P_POSITION;
+    static const QString T_TRANSFORMATION;
+
+protected:
+    ItemWithParticles(const QString& model_type, const QString& abundance_tooltip,
+                      const QString& position_tooltip);
+
+private:
+    virtual bool isShellParticle() const;
+};
+
+#endif // BORNAGAIN_GUI_MODELS_ITEMWITHMATERIAL_H
diff --git a/GUI/Models/LayerItem.cpp b/GUI/Models/LayerItem.cpp
index 0f0119ec57113a5c4d6d4d14a2e73ad1786374fc..d7478fbbf44b12338ca54055bc16260ecafd050f 100644
--- a/GUI/Models/LayerItem.cpp
+++ b/GUI/Models/LayerItem.cpp
@@ -30,7 +30,7 @@ const QString LayerItem::T_LAYOUTS = "Layout tag";
 
 const QString LayerItem::M_TYPE = "Layer";
 
-LayerItem::LayerItem() : ItemWithMaterial(M_TYPE)
+LayerItem::LayerItem() : SessionGraphicsItem(M_TYPE), ItemWithMaterial(M_TYPE)
 {
     setToolTip("A layer with thickness and material");
     addProperty(P_THICKNESS, 0.0)
diff --git a/GUI/Models/MaterialItemUtils.cpp b/GUI/Models/MaterialItemUtils.cpp
index 76929fece518851587cba383ec76a2c0a6b0db55..653d34075f1d464860334044df8298965ac3fd2a 100644
--- a/GUI/Models/MaterialItemUtils.cpp
+++ b/GUI/Models/MaterialItemUtils.cpp
@@ -160,9 +160,9 @@ QVector<SessionItem*> GUI::Model::MaterialItemUtils::materialPropertyItems(Sessi
         }
 
         if (model_type == ParticleItem::M_TYPE)
-            materials.append(static_cast<ParticleItem*>(item)->materialPropertyItems());
+            materials.append(dynamic_cast<ParticleItem*>(item)->materialPropertyItems());
         else if (model_type == "ParticleCoreShell")
-            materials.append(static_cast<ParticleCoreShellItem*>(item)->materialPropertyItems());
+            materials.append(dynamic_cast<ParticleCoreShellItem*>(item)->materialPropertyItems());
         else
             throw Error("Error in GUI::Model::MaterialItemUtils::materialProperties: cannot handle "
                         "passed model type '"
diff --git a/GUI/Models/MaterialPropertyController.cpp b/GUI/Models/MaterialPropertyController.cpp
index a497f2721e598e4ffdcdcb0e112af8221a650623..c74dd5dca320e40eb177afbdcba51793212c3aef 100644
--- a/GUI/Models/MaterialPropertyController.cpp
+++ b/GUI/Models/MaterialPropertyController.cpp
@@ -22,7 +22,7 @@
 #include <QVector>
 
 #include <boost/polymorphic_cast.hpp>
-using boost::polymorphic_downcast;
+using boost::polymorphic_cast;
 
 MaterialPropertyController::MaterialPropertyController(QObject* parent)
     : QObject(parent), m_materialModel(nullptr), m_sampleModel(nullptr)
@@ -124,7 +124,7 @@ QVector<ItemWithMaterial*> MaterialPropertyController::relatedSampleItems()
 
         if (SessionItem* item = m_sampleModel->itemForIndex(index))
             if (materialRelated.contains(item->modelType()))
-                result.push_back(polymorphic_downcast<ItemWithMaterial*>(item));
+                result.push_back(polymorphic_cast<ItemWithMaterial*>(item));
     });
 
     return result;
diff --git a/GUI/Models/MesoCrystalItem.cpp b/GUI/Models/MesoCrystalItem.cpp
index b0317757cc6eb36b274def82d64e5c17a3a8fb3d..853034a82114e58c8be84caa4c72a2416a23fc7b 100644
--- a/GUI/Models/MesoCrystalItem.cpp
+++ b/GUI/Models/MesoCrystalItem.cpp
@@ -52,23 +52,17 @@ const QString MesoCrystalItem::P_VECTOR_A = "First lattice vector";
 const QString MesoCrystalItem::P_VECTOR_B = "Second lattice vector";
 const QString MesoCrystalItem::P_VECTOR_C = "Third lattice vector";
 
-// TODO make derived from ParticleItem
-
-MesoCrystalItem::MesoCrystalItem() : SessionGraphicsItem("MesoCrystal")
+MesoCrystalItem::MesoCrystalItem()
+    : SessionGraphicsItem("MesoCrystal"),
+      ItemWithParticles("MesoCrystal", abundance_tooltip, position_tooltip)
 {
     setToolTip("A 3D crystal structure of nanoparticles");
 
     addGroupProperty(P_OUTER_SHAPE, "Form Factor");
 
-    addProperty(ParticleItem::P_ABUNDANCE, 1.0)
-        ->setLimits(RealLimits::limited(0.0, 1.0))
-        .setDecimals(3)
-        .setToolTip(abundance_tooltip);
-
     addProperty<VectorItem>(P_VECTOR_A)->setToolTip(lattice_vector1_tooltip);
     addProperty<VectorItem>(P_VECTOR_B)->setToolTip(lattice_vector2_tooltip);
     addProperty<VectorItem>(P_VECTOR_C)->setToolTip(lattice_vector3_tooltip);
-    addProperty<VectorItem>(ParticleItem::P_POSITION)->setToolTip(position_tooltip);
 
     registerTag(T_BASIS_PARTICLE, 0, 1,
                 QStringList() << ParticleItem::M_TYPE
@@ -76,22 +70,11 @@ MesoCrystalItem::MesoCrystalItem() : SessionGraphicsItem("MesoCrystal")
                               << "ParticleComposition"
                               << "MesoCrystal");
     setDefaultTag(T_BASIS_PARTICLE);
-
-    registerTag(ParticleItem::T_TRANSFORMATION, 0, 1, QStringList() << "Rotation");
-
-    mapper()->setOnParentChange([this](SessionItem* parent) {
-        if (GUI::Session::ItemUtils::HasOwnAbundance(parent)) {
-            setItemValue(ParticleItem::P_ABUNDANCE, 1.0);
-            getItem(ParticleItem::P_ABUNDANCE)->setEnabled(false);
-        } else {
-            getItem(ParticleItem::P_ABUNDANCE)->setEnabled(true);
-        }
-    });
 }
 
 VectorItem* MesoCrystalItem::positionItem() const
 {
-    return item<VectorItem>(ParticleItem::P_POSITION);
+    return item<VectorItem>(P_POSITION);
 }
 
 std::unique_ptr<MesoCrystal> MesoCrystalItem::createMesoCrystal() const
@@ -130,16 +113,16 @@ std::unique_ptr<IParticle> MesoCrystalItem::getBasis() const
     QVector<SessionItem*> childlist = children();
     for (int i = 0; i < childlist.size(); ++i) {
         if (childlist[i]->hasModelType<ParticleItem>()) {
-            auto* particle_item = static_cast<ParticleItem*>(childlist[i]);
+            auto* particle_item = dynamic_cast<ParticleItem*>(childlist[i]);
             return particle_item->createParticle();
         } else if (childlist[i]->modelType() == "ParticleCoreShell") {
-            auto* particle_coreshell_item = static_cast<ParticleCoreShellItem*>(childlist[i]);
+            auto* particle_coreshell_item = dynamic_cast<ParticleCoreShellItem*>(childlist[i]);
             return particle_coreshell_item->createParticleCoreShell();
         } else if (childlist[i]->modelType() == "ParticleComposition") {
-            auto* particlecomposition_item = static_cast<ParticleCompositionItem*>(childlist[i]);
+            auto* particlecomposition_item = dynamic_cast<ParticleCompositionItem*>(childlist[i]);
             return particlecomposition_item->createParticleComposition();
         } else if (childlist[i]->modelType() == "MesoCrystal") {
-            auto* mesocrystal_item = static_cast<MesoCrystalItem*>(childlist[i]);
+            auto* mesocrystal_item = dynamic_cast<MesoCrystalItem*>(childlist[i]);
             return mesocrystal_item->createMesoCrystal();
         }
     }
diff --git a/GUI/Models/MesoCrystalItem.h b/GUI/Models/MesoCrystalItem.h
index 4b8a3a7b0d165e33bbd51a3d2a6f02ec8e6b5ac8..84bf240d95327b438aa0918591250fdb0392ed06 100644
--- a/GUI/Models/MesoCrystalItem.h
+++ b/GUI/Models/MesoCrystalItem.h
@@ -15,7 +15,7 @@
 #ifndef BORNAGAIN_GUI_MODELS_MESOCRYSTALITEM_H
 #define BORNAGAIN_GUI_MODELS_MESOCRYSTALITEM_H
 
-#include "GUI/Models/SessionGraphicsItem.h"
+#include "GUI/Models/ItemWithParticles.h"
 #include "Sample/Lattice/Lattice3D.h"
 
 class IFormFactor;
@@ -23,7 +23,7 @@ class IParticle;
 class MesoCrystal;
 class VectorItem;
 
-class BA_CORE_API_ MesoCrystalItem : public SessionGraphicsItem {
+class BA_CORE_API_ MesoCrystalItem : public ItemWithParticles {
 public:
     static const QString P_OUTER_SHAPE;
     static const QString T_BASIS_PARTICLE;
diff --git a/GUI/Models/MultiLayerItem.cpp b/GUI/Models/MultiLayerItem.cpp
index 64d12559ab16665187a26d966d1cbee4168d3548..ab72da339c78711f97dee16d670689e5797eb050 100644
--- a/GUI/Models/MultiLayerItem.cpp
+++ b/GUI/Models/MultiLayerItem.cpp
@@ -48,7 +48,7 @@ QVector<SessionItem*> MultiLayerItem::materialPropertyItems()
 {
     QVector<SessionItem*> result;
     for (auto layer_item : getItems(T_LAYERS))
-        result.append(static_cast<LayerItem*>(layer_item)->materialPropertyItems());
+        result.append(dynamic_cast<LayerItem*>(layer_item)->materialPropertyItems());
     return result;
 }
 
diff --git a/GUI/Models/ParticleCompositionItem.cpp b/GUI/Models/ParticleCompositionItem.cpp
index 6268d8bd256c186821abeb2b858d9046a1f00043..48d36de52d817a34c27be63ba28b1e99d8b9aa1e 100644
--- a/GUI/Models/ParticleCompositionItem.cpp
+++ b/GUI/Models/ParticleCompositionItem.cpp
@@ -33,69 +33,52 @@ const QString position_tooltip = "Relative position of the particle's reference
 
 const QString ParticleCompositionItem::T_PARTICLES = "Particle Tag";
 
-// TODO make ParticleCoreShellItem and ParticleItem to derive from common base.
-
-ParticleCompositionItem::ParticleCompositionItem() : SessionGraphicsItem("ParticleComposition")
+ParticleCompositionItem::ParticleCompositionItem()
+    : SessionGraphicsItem("ParticleComposition"),
+      ItemWithParticles("ParticleComposition", abundance_tooltip, position_tooltip)
 {
     setToolTip("Composition of particles with fixed positions");
 
-    addProperty(ParticleItem::P_ABUNDANCE, 1.0)
-        ->setLimits(RealLimits::limited(0.0, 1.0))
-        .setDecimals(3)
-        .setToolTip(abundance_tooltip);
-
-    addProperty<VectorItem>(ParticleItem::P_POSITION)->setToolTip(position_tooltip);
-
     registerTag(T_PARTICLES, 0, -1,
                 QStringList() << ParticleItem::M_TYPE
                               << "ParticleCoreShell"
                               << "ParticleComposition"
                               << "MesoCrystal");
     setDefaultTag(T_PARTICLES);
-    registerTag(ParticleItem::T_TRANSFORMATION, 0, 1, QStringList() << "Rotation");
-
-    mapper()->setOnParentChange([this](SessionItem* parent) {
-        if (GUI::Session::ItemUtils::HasOwnAbundance(parent)) {
-            setItemValue(ParticleItem::P_ABUNDANCE, 1.0);
-            getItem(ParticleItem::P_ABUNDANCE)->setEnabled(false);
-        } else {
-            getItem(ParticleItem::P_ABUNDANCE)->setEnabled(true);
-        }
-    });
 }
 
 VectorItem* ParticleCompositionItem::positionItem() const
 {
-    return item<VectorItem>(ParticleItem::P_POSITION);
+    return item<VectorItem>(P_POSITION);
 }
 
 std::unique_ptr<ParticleComposition> ParticleCompositionItem::createParticleComposition() const
 {
-    double abundance = getItemValue(ParticleItem::P_ABUNDANCE).toDouble();
+    double abundance = getItemValue(P_ABUNDANCE).toDouble();
     auto P_composition = std::make_unique<ParticleComposition>();
     P_composition->setAbundance(abundance);
     QVector<SessionItem*> childlist = children();
     for (int i = 0; i < childlist.size(); ++i) {
         if (childlist[i]->hasModelType<ParticleItem>()) {
-            auto* particle_item = static_cast<ParticleItem*>(childlist[i]);
+            auto* particle_item = dynamic_cast<ParticleItem*>(childlist[i]);
             auto P_particle = particle_item->createParticle();
             if (P_particle) {
                 P_composition->addParticle(*P_particle);
             }
         } else if (childlist[i]->modelType() == "ParticleCoreShell") {
-            auto* particle_coreshell_item = static_cast<ParticleCoreShellItem*>(childlist[i]);
+            auto* particle_coreshell_item = dynamic_cast<ParticleCoreShellItem*>(childlist[i]);
             auto P_particle_coreshell = particle_coreshell_item->createParticleCoreShell();
             if (P_particle_coreshell) {
                 P_composition->addParticle(*P_particle_coreshell);
             }
         } else if (childlist[i]->modelType() == "ParticleComposition") {
-            auto* particlecomposition_item = static_cast<ParticleCompositionItem*>(childlist[i]);
+            auto* particlecomposition_item = dynamic_cast<ParticleCompositionItem*>(childlist[i]);
             auto P_child_composition = particlecomposition_item->createParticleComposition();
             if (P_child_composition) {
                 P_composition->addParticle(*P_child_composition);
             }
         } else if (childlist[i]->modelType() == "MesoCrystal") {
-            auto* mesocrystal_item = static_cast<MesoCrystalItem*>(childlist[i]);
+            auto* mesocrystal_item = dynamic_cast<MesoCrystalItem*>(childlist[i]);
             auto P_child_meso = mesocrystal_item->createMesoCrystal();
             if (P_child_meso) {
                 P_composition->addParticle(*P_child_meso);
diff --git a/GUI/Models/ParticleCompositionItem.h b/GUI/Models/ParticleCompositionItem.h
index 97d37c9d07776d2548ff98e916b8afe91b593a29..2e0f6ad4c7d712272bc8e3cde7b01694b1fb3a75 100644
--- a/GUI/Models/ParticleCompositionItem.h
+++ b/GUI/Models/ParticleCompositionItem.h
@@ -15,12 +15,12 @@
 #ifndef BORNAGAIN_GUI_MODELS_PARTICLECOMPOSITIONITEM_H
 #define BORNAGAIN_GUI_MODELS_PARTICLECOMPOSITIONITEM_H
 
-#include "GUI/Models/SessionGraphicsItem.h"
+#include "GUI/Models/ItemWithParticles.h"
 #include "Sample/Particle/ParticleComposition.h"
 
 class VectorItem;
 
-class BA_CORE_API_ ParticleCompositionItem : public SessionGraphicsItem {
+class BA_CORE_API_ ParticleCompositionItem : public ItemWithParticles {
 public:
     static const QString T_PARTICLES;
     ParticleCompositionItem();
diff --git a/GUI/Models/ParticleCoreShellItem.cpp b/GUI/Models/ParticleCoreShellItem.cpp
index 525363a464a7e149a549f587577e1298dc43bc67..88ca0c1e559dc3f66bc0ddff93d53fa398c2ee2d 100644
--- a/GUI/Models/ParticleCoreShellItem.cpp
+++ b/GUI/Models/ParticleCoreShellItem.cpp
@@ -34,41 +34,24 @@ const QString position_tooltip = "Relative position of the particle's reference
 const QString ParticleCoreShellItem::T_CORE = "Core tag";
 const QString ParticleCoreShellItem::T_SHELL = "Shell tag";
 
-// TODO make ParticleCoreShellItem and ParticleItem to derive from common base.
-
-ParticleCoreShellItem::ParticleCoreShellItem() : SessionGraphicsItem("ParticleCoreShell")
+ParticleCoreShellItem::ParticleCoreShellItem()
+    : SessionGraphicsItem("ParticleCoreShell"),
+      ItemWithParticles("ParticleCoreShell", abundance_tooltip, position_tooltip)
 {
     setToolTip("A particle with a core/shell geometry");
 
-    addProperty(ParticleItem::P_ABUNDANCE, 1.0)
-        ->setLimits(RealLimits::limited(0.0, 1.0))
-        .setDecimals(3)
-        .setToolTip(abundance_tooltip);
-
-    addProperty<VectorItem>(ParticleItem::P_POSITION)->setToolTip(position_tooltip);
-
     registerTag(T_CORE, 0, 1, {ParticleItem::M_TYPE});
     registerTag(T_SHELL, 0, 1, {ParticleItem::M_TYPE});
-    registerTag(ParticleItem::T_TRANSFORMATION, 0, 1, QStringList() << "Rotation");
-
-    mapper()->setOnParentChange([this](SessionItem* parent) {
-        if (GUI::Session::ItemUtils::HasOwnAbundance(parent)) {
-            setItemValue(ParticleItem::P_ABUNDANCE, 1.0);
-            getItem(ParticleItem::P_ABUNDANCE)->setEnabled(false);
-        } else {
-            getItem(ParticleItem::P_ABUNDANCE)->setEnabled(true);
-        }
-    });
 }
 
 VectorItem* ParticleCoreShellItem::positionItem() const
 {
-    return item<VectorItem>(ParticleItem::P_POSITION);
+    return item<VectorItem>(P_POSITION);
 }
 
 std::unique_ptr<ParticleCoreShell> ParticleCoreShellItem::createParticleCoreShell() const
 {
-    double abundance = getItemValue(ParticleItem::P_ABUNDANCE).toDouble();
+    double abundance = getItemValue(P_ABUNDANCE).toDouble();
     std::unique_ptr<Particle> P_core{};
     std::unique_ptr<Particle> P_shell{};
     auto core_item = dynamic_cast<ParticleItem*>(getItem(T_CORE));
@@ -89,10 +72,10 @@ std::unique_ptr<ParticleCoreShell> ParticleCoreShellItem::createParticleCoreShel
 QVector<SessionItem*> ParticleCoreShellItem::materialPropertyItems()
 {
     QVector<SessionItem*> result;
-    if (auto core = static_cast<ParticleItem*>(getItem(T_CORE)))
+    if (auto core = dynamic_cast<ParticleItem*>(getItem(T_CORE)))
         result.append(core->materialPropertyItems());
 
-    if (auto shell = static_cast<ParticleItem*>(getItem(T_SHELL)))
+    if (auto shell = dynamic_cast<ParticleItem*>(getItem(T_SHELL)))
         result.append(shell->materialPropertyItems());
 
     return result;
diff --git a/GUI/Models/ParticleCoreShellItem.h b/GUI/Models/ParticleCoreShellItem.h
index 41278e3170e03837a9c59b580625f493b506d32e..1e0048127875d6e494f64d5448b7c568c1d03d8d 100644
--- a/GUI/Models/ParticleCoreShellItem.h
+++ b/GUI/Models/ParticleCoreShellItem.h
@@ -15,12 +15,12 @@
 #ifndef BORNAGAIN_GUI_MODELS_PARTICLECORESHELLITEM_H
 #define BORNAGAIN_GUI_MODELS_PARTICLECORESHELLITEM_H
 
-#include "GUI/Models/SessionGraphicsItem.h"
+#include "GUI/Models/ItemWithParticles.h"
 
 class ParticleCoreShell;
 class VectorItem;
 
-class BA_CORE_API_ ParticleCoreShellItem : public SessionGraphicsItem {
+class BA_CORE_API_ ParticleCoreShellItem : public ItemWithParticles {
 public:
     static const QString T_CORE;
     static const QString T_SHELL;
diff --git a/GUI/Models/ParticleItem.cpp b/GUI/Models/ParticleItem.cpp
index eb15c372bb3dfd185bbc807ad2d27d8c4bcf1dc1..ef8cca506a092884241f343d90f35128b08cc907 100644
--- a/GUI/Models/ParticleItem.cpp
+++ b/GUI/Models/ParticleItem.cpp
@@ -33,27 +33,16 @@ const QString position_tooltip = "Relative position of the particle's reference
 } // namespace
 
 const QString ParticleItem::P_FORM_FACTOR = "Form Factor";
-const QString ParticleItem::P_ABUNDANCE = QString::fromStdString("Abundance");
-const QString ParticleItem::P_POSITION = "Position Offset";
-const QString ParticleItem::T_TRANSFORMATION = "Transformation Tag";
 
 const QString ParticleItem::M_TYPE = "Particle";
 
-ParticleItem::ParticleItem() : ItemWithMaterial(M_TYPE)
+ParticleItem::ParticleItem()
+    : SessionGraphicsItem(M_TYPE), ItemWithMaterial(M_TYPE),
+      ItemWithParticles(M_TYPE, abundance_tooltip, position_tooltip)
 {
     addGroupProperty(P_FORM_FACTOR, "Form Factor");
 
-    addProperty(P_ABUNDANCE, 1.0)
-        ->setLimits(RealLimits::limited(0.0, 1.0))
-        .setDecimals(3)
-        .setToolTip(abundance_tooltip);
-    addProperty<VectorItem>(P_POSITION)->setToolTip(position_tooltip);
-
-    registerTag(T_TRANSFORMATION, 0, 1, QStringList() << "Rotation");
     setDefaultTag(T_TRANSFORMATION);
-
-    mapper()->setOnParentChange(
-        [this](SessionItem* newParent) { updatePropertiesAppearance(newParent); });
 }
 
 VectorItem* ParticleItem::positionItem() const
@@ -63,9 +52,9 @@ VectorItem* ParticleItem::positionItem() const
 
 std::unique_ptr<Particle> ParticleItem::createParticle() const
 {
-    auto& ffItem = groupItem<FormFactorItem>(ParticleItem::P_FORM_FACTOR);
+    auto& ffItem = groupItem<FormFactorItem>(P_FORM_FACTOR);
     auto material = GUI::Transform::ToDomain::createDomainMaterial(*this);
-    double abundance = getItemValue(ParticleItem::P_ABUNDANCE).toDouble();
+    double abundance = getItemValue(P_ABUNDANCE).toDouble();
 
     auto particle = std::make_unique<Particle>(*material, *ffItem.createFormFactor());
     particle->setAbundance(abundance);
@@ -103,24 +92,6 @@ GroupItem* ParticleItem::formFactorItem() const
     return item<GroupItem>(P_FORM_FACTOR);
 }
 
-//! Updates enabled/disabled for particle position and particle abundance depending on context.
-
-void ParticleItem::updatePropertiesAppearance(SessionItem* newParent)
-{
-    if (GUI::Session::ItemUtils::HasOwnAbundance(newParent)) {
-        setItemValue(ParticleItem::P_ABUNDANCE, 1.0);
-        getItem(ParticleItem::P_ABUNDANCE)->setEnabled(false);
-        if (isShellParticle()) {
-            auto pos = positionItem();
-            pos->setVector(kvector_t());
-            pos->setEnabled(false);
-        }
-    } else {
-        getItem(ParticleItem::P_ABUNDANCE)->setEnabled(true);
-        positionItem()->setEnabled(true);
-    }
-}
-
 //! Returns true if this particle is a shell particle.
 
 bool ParticleItem::isShellParticle() const
diff --git a/GUI/Models/ParticleItem.h b/GUI/Models/ParticleItem.h
index 93cf29c582514266763a0b4623611d9a7c6bc413..a9035e65d3a81439d56526da57ae36df61a2a2a5 100644
--- a/GUI/Models/ParticleItem.h
+++ b/GUI/Models/ParticleItem.h
@@ -16,21 +16,18 @@
 #define BORNAGAIN_GUI_MODELS_PARTICLEITEM_H
 
 #include "GUI/Models/ItemWithMaterial.h"
+#include "GUI/Models/ItemWithParticles.h"
 
 class FormFactorItem;
 class GroupItem;
 class Particle;
 class VectorItem;
 
-class BA_CORE_API_ ParticleItem : public ItemWithMaterial {
+class BA_CORE_API_ ParticleItem : public ItemWithMaterial, public ItemWithParticles {
 private:
     static const QString P_FORM_FACTOR;
 
 public:
-    static const QString P_ABUNDANCE;
-    static const QString P_POSITION;
-    static const QString T_TRANSFORMATION;
-
     static const QString M_TYPE;
 
     ParticleItem();
@@ -47,8 +44,7 @@ public:
     GroupItem* formFactorItem() const;
 
 private:
-    void updatePropertiesAppearance(SessionItem*);
-    bool isShellParticle() const;
+    virtual bool isShellParticle() const override;
     bool parentIsParticleLayout() const;
 };
 
diff --git a/GUI/Models/SessionItem.h b/GUI/Models/SessionItem.h
index e02ca42254e17ccbbaa2957bfba6a57cfd36a82c..dd01e885c216e32a566c3732080531fda1c6170e 100644
--- a/GUI/Models/SessionItem.h
+++ b/GUI/Models/SessionItem.h
@@ -343,7 +343,7 @@ template <typename T> QVector<T*> SessionItem::childrenOfType() const
     QVector<T*> result;
     for (auto child : m_children)
         if (child->modelType() == T::M_TYPE)
-            result.append(static_cast<T*>(child));
+            result.append(dynamic_cast<T*>(child));
 
     return result;
 }
diff --git a/GUI/Models/SessionModel.h b/GUI/Models/SessionModel.h
index dd677eac37fbd2a0cd7d4ff9a9a55af684404405..049a86fb9a08cbebc05f330899b169a07e88166d 100644
--- a/GUI/Models/SessionModel.h
+++ b/GUI/Models/SessionModel.h
@@ -139,7 +139,7 @@ private:
 
 template <typename T> T* SessionModel::insertItem(SessionItem* parent, int row, QString tag)
 {
-    return static_cast<T*>(insertNewItem(T().modelType(), parent, row, tag));
+    return dynamic_cast<T*>(insertNewItem(T().modelType(), parent, row, tag));
 }
 
 template <typename T> T* SessionModel::insertItem(const QModelIndex& parent, int row, QString tag)
diff --git a/GUI/Models/TransformToDomain.cpp b/GUI/Models/TransformToDomain.cpp
index 4cdf23197d94f36868b3867d1d5506b30d543b41..ea7b67e6b67edd73c3de467f8d5d76f60e870287 100644
--- a/GUI/Models/TransformToDomain.cpp
+++ b/GUI/Models/TransformToDomain.cpp
@@ -108,16 +108,16 @@ std::unique_ptr<IParticle> GUI::Transform::ToDomain::createIParticle(const Sessi
 {
     std::unique_ptr<IParticle> P_particle;
     if (item.hasModelType<ParticleItem>()) {
-        auto& particle_item = static_cast<const ParticleItem&>(item);
+        auto& particle_item = dynamic_cast<const ParticleItem&>(item);
         P_particle = particle_item.createParticle();
     } else if (item.modelType() == "ParticleCoreShell") {
-        auto& particle_coreshell_item = static_cast<const ParticleCoreShellItem&>(item);
+        auto& particle_coreshell_item = dynamic_cast<const ParticleCoreShellItem&>(item);
         P_particle = particle_coreshell_item.createParticleCoreShell();
     } else if (item.modelType() == "ParticleComposition") {
-        auto& particle_composition_item = static_cast<const ParticleCompositionItem&>(item);
+        auto& particle_composition_item = dynamic_cast<const ParticleCompositionItem&>(item);
         P_particle = particle_composition_item.createParticleComposition();
     } else if (item.modelType() == "MesoCrystal") {
-        auto& mesocrystal_item = static_cast<const MesoCrystalItem&>(item);
+        auto& mesocrystal_item = dynamic_cast<const MesoCrystalItem&>(item);
         P_particle = mesocrystal_item.createMesoCrystal();
     }
     return P_particle;
diff --git a/GUI/Views/SampleDesigner/ParticleView.cpp b/GUI/Views/SampleDesigner/ParticleView.cpp
index e35a848df26967569eda7bdd024df970a612c6a6..65a5f81292856cc24b7407e596cd9c95bdabbaf6 100644
--- a/GUI/Views/SampleDesigner/ParticleView.cpp
+++ b/GUI/Views/SampleDesigner/ParticleView.cpp
@@ -97,7 +97,7 @@ void ParticleView::updatePixmap()
     if (!getItem())
         return;
 
-    QString ff_type = static_cast<ParticleItem*>(getItem())->formFactorItem()->currentType();
+    QString ff_type = dynamic_cast<ParticleItem*>(getItem())->formFactorItem()->currentType();
     QString filename = QString(":/widgetbox/images/ff_%1_64x64.png").arg(ff_type);
     m_pixmap = QPixmap(filename);
 }
@@ -107,6 +107,6 @@ void ParticleView::updateToolTip()
     if (!getItem())
         return;
 
-    auto ffItem = static_cast<ParticleItem*>(getItem())->formFactorItem()->currentItem();
+    auto ffItem = dynamic_cast<ParticleItem*>(getItem())->formFactorItem()->currentItem();
     setToolTip(ffItem->toolTip());
 }
diff --git a/Tests/UnitTests/GUI/TestComponentUtils.cpp b/Tests/UnitTests/GUI/TestComponentUtils.cpp
index 011c75f1411b21efebeb222bdedc5199540353cc..5168878ba3ad249e06580a0df1fb1ce931ec6023 100644
--- a/Tests/UnitTests/GUI/TestComponentUtils.cpp
+++ b/Tests/UnitTests/GUI/TestComponentUtils.cpp
@@ -21,11 +21,14 @@ TEST_F(TestComponentUtils, test_componentItems)
     CylinderItem* ffCylinder = dynamic_cast<CylinderItem*>(ffItem);
     EXPECT_NE(ffCylinder, nullptr);
 
-    QList<const SessionItem*> expectedList = QList<const SessionItem*>()
-                                             << particle->materialItem() << group
-                                             << ffCylinder->radiusItem() << ffCylinder->heightItem()
-                                             << particle->getItem(ParticleItem::P_ABUNDANCE)
-                                             << particle->getItem(ParticleItem::P_POSITION);
+    QList<const SessionItem*> expectedList =
+        QList<const SessionItem*>()
+        << particle->materialItem()
+        << particle->getItem(ParticleItem::P_ABUNDANCE)
+        << particle->getItem(ParticleItem::P_POSITION)
+        << group
+        << ffCylinder->radiusItem()
+        << ffCylinder->heightItem();
 
     auto itemList = GUI::Model::ComponentUtils::componentItems(*particle);
     EXPECT_EQ(itemList.size(), 6);
@@ -42,10 +45,12 @@ TEST_F(TestComponentUtils, test_componentItemsFFChange)
     particle->setFormFactorType<FullSphereItem>();
     FullSphereItem* sphereItem = dynamic_cast<FullSphereItem*>(particle->formFactor());
 
-    QList<const SessionItem*> expectedList =
-        QList<const SessionItem*>() << particle->materialItem() << group << sphereItem->radiusItem()
-                                    << particle->getItem(ParticleItem::P_ABUNDANCE)
-                                    << particle->getItem(ParticleItem::P_POSITION);
+    QList<const SessionItem*> expectedList = QList<const SessionItem*>()
+                                             << particle->materialItem()
+                                             << particle->getItem(ParticleItem::P_ABUNDANCE)
+                                             << particle->getItem(ParticleItem::P_POSITION)
+                                             << group
+                                             << sphereItem->radiusItem();
 
     auto itemList = GUI::Model::ComponentUtils::componentItems(*particle);
     EXPECT_EQ(itemList.size(), 5);