diff --git a/GUI/Model/Sample/InterferenceItemCatalog.cpp b/GUI/Model/Sample/InterferenceItemCatalog.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..997fc24f8c77f8161431aa588ba0287e1aa9bd11
--- /dev/null
+++ b/GUI/Model/Sample/InterferenceItemCatalog.cpp
@@ -0,0 +1,104 @@
+//  ************************************************************************************************
+//
+//  BornAgain: simulate and fit reflection and scattering
+//
+//! @file      GUI/Model/Sample/InterferenceItemCatalog.cpp
+//! @brief     Implements class InterferenceItemCatalog
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2021
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+//  ************************************************************************************************
+
+#include "GUI/Model/Sample/InterferenceItemCatalog.h"
+#include "GUI/Model/Sample/InterferenceItems.h"
+
+InterferenceItem* InterferenceItemCatalog::create(Type type)
+{
+    switch (type) {
+    case Type::None:
+        return nullptr;
+    case Type::RadialParaCrystalRadial:
+        return new InterferenceRadialParaCrystalItem();
+    case Type::ParaCrystal2D:
+        return new Interference2DParaCrystalItem();
+    case Type::Lattice1D:
+        return new Interference1DLatticeItem();
+    case Type::Lattice2D:
+        return new Interference2DLatticeItem();
+    case Type::FiniteLattice2D:
+        return new InterferenceFinite2DLatticeItem();
+    case Type::HardDisk:
+        return new InterferenceHardDiskItem();
+    default:
+        ASSERT(false);
+    }
+}
+
+QVector<InterferenceItemCatalog::Type> InterferenceItemCatalog::types()
+{
+    return {Type::None,      Type::RadialParaCrystalRadial, Type::Lattice1D,
+            Type::Lattice2D, Type::FiniteLattice2D,         Type::ParaCrystal2D,
+            Type::HardDisk};
+}
+
+InterferenceItemCatalog::UiInfo InterferenceItemCatalog::uiInfo(Type type)
+{
+    auto createUiInfo = [](const QString& menuEntry, const QString& iconPath,
+                           const QString& description) {
+        UiInfo info;
+        info.menuEntry = menuEntry;
+        info.iconPath = iconPath;
+        info.description = description;
+        return info;
+    };
+
+    switch (type) {
+    case Type::None:
+        return createUiInfo("None", "", "");
+    case Type::RadialParaCrystalRadial:
+        return createUiInfo("Radial paracrystal",
+                            ":/SampleDesignerToolbox/images/ParaCrystal1D.png",
+                            "Interference function of radial paracrystal");
+    case Type::ParaCrystal2D:
+        return createUiInfo("2D paracrystal", ":/SampleDesignerToolbox/images/ParaCrystal2D.png",
+                            "Interference function of two-dimensional paracrystal");
+    case Type::Lattice1D:
+        return createUiInfo("1D lattice", ":/SampleDesignerToolbox/images/Lattice1D.png",
+                            "Interference function of 1D lattice");
+    case Type::Lattice2D:
+        return createUiInfo("2D lattice", ":/SampleDesignerToolbox/images/Lattice2D.png",
+                            "Interference function of 2D lattice");
+    case Type::FiniteLattice2D:
+        return createUiInfo("Finite 2D lattice",
+                            ":/SampleDesignerToolbox/images/Lattice2DFinite.png",
+                            "Interference function of finite 2D lattice");
+    case Type::HardDisk:
+        return createUiInfo("Hard disk Percus-Yevick",
+                            ":/SampleDesignerToolbox/images/Lattice2D.png",
+                            "Interference function for hard disk Percus-Yevick");
+    default:
+        ASSERT(false);
+    }
+}
+
+InterferenceItemCatalog::Type InterferenceItemCatalog::type(InterferenceItem* item)
+{
+    if (!item)
+        return Type::None;
+
+#define CHECK(itfClass, type)                                                                      \
+    if (dynamic_cast<itfClass*>(item))                                                             \
+    return Type::type
+
+    CHECK(InterferenceRadialParaCrystalItem, RadialParaCrystalRadial);
+    CHECK(Interference2DParaCrystalItem, ParaCrystal2D);
+    CHECK(Interference1DLatticeItem, Lattice1D);
+    CHECK(Interference2DLatticeItem, Lattice2D);
+    CHECK(InterferenceFinite2DLatticeItem, FiniteLattice2D);
+    CHECK(InterferenceHardDiskItem, HardDisk);
+#undef CHECK
+    ASSERT(false);
+}
diff --git a/GUI/Model/Sample/InterferenceItemCatalog.h b/GUI/Model/Sample/InterferenceItemCatalog.h
new file mode 100644
index 0000000000000000000000000000000000000000..e5b7a85e56d3876bf50b5a157f6109ea64c0bc10
--- /dev/null
+++ b/GUI/Model/Sample/InterferenceItemCatalog.h
@@ -0,0 +1,62 @@
+//  ************************************************************************************************
+//
+//  BornAgain: simulate and fit reflection and scattering
+//
+//! @file      GUI/Model/Sample/InterferenceItemCatalog.h
+//! @brief     Defines class InterferenceItemCatalog
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2021
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+//  ************************************************************************************************
+
+#ifndef BORNAGAIN_GUI_MODEL_SAMPLE_INTERFERENCEITEMCATALOG_H
+#define BORNAGAIN_GUI_MODEL_SAMPLE_INTERFERENCEITEMCATALOG_H
+
+#include <QString>
+
+class InterferenceItem;
+
+class InterferenceItemCatalog {
+public:
+    using CatalogedType = InterferenceItem;
+
+    // Do not change the numbering! It is serialized!
+    enum class Type : uint8_t {
+        None = 0,
+        RadialParaCrystalRadial = 1,
+        ParaCrystal2D = 2,
+        Lattice1D = 3,
+        Lattice2D = 4,
+        FiniteLattice2D = 5,
+        HardDisk = 6
+    };
+
+    struct UiInfo {
+        QString menuEntry;
+        QString description;
+        QString iconPath;
+    };
+
+
+    //! Creates the item of the given type.
+    //!
+    //! If type is "None", a nullptr is returned.
+    static InterferenceItem* create(Type type);
+
+    //! Available types of interference items.
+    //!
+    //! Contains also type "None".
+    //! This list is sorted as expected in the UI (e.g. in combo box)
+    static QVector<Type> types();
+
+    //! UiInfo on the given type.
+    static UiInfo uiInfo(Type t);
+
+    //! Returns the enum type of the given item.
+    static Type type(InterferenceItem* item);
+};
+
+#endif // BORNAGAIN_GUI_MODEL_SAMPLE_INTERFERENCEITEMCATALOG_H
diff --git a/GUI/Model/Sample/InterferenceItems.cpp b/GUI/Model/Sample/InterferenceItems.cpp
index c9f3e65a3b797adb6cb29f51f7cc973c93068fa0..0b446a09149824f9f47a5ed84736f1ea9146ccb8 100644
--- a/GUI/Model/Sample/InterferenceItems.cpp
+++ b/GUI/Model/Sample/InterferenceItems.cpp
@@ -7,132 +7,109 @@
 //!
 //! @homepage  http://www.bornagainproject.org
 //! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @copyright Forschungszentrum Jülich GmbH 2021
 //! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
 //
 //  ************************************************************************************************
 
 #include "GUI/Model/Sample/InterferenceItems.h"
 #include "Base/Const/Units.h"
+#include "GUI/Model/Sample/FTDecayFunctionItemCatalogs.h"
 #include "GUI/Model/Sample/FTDecayFunctionItems.h"
+#include "GUI/Model/Sample/FTDistributionItemCatalogs.h"
 #include "GUI/Model/Sample/FTDistributionItems.h"
+#include "GUI/Model/Sample/Lattice2DItemCatalog.h"
 #include "GUI/Model/Sample/Lattice2DItems.h"
 #include "GUI/Model/Types/UIntDescriptor.h"
 #include "Sample/Aggregate/Interferences.h"
 
-// TODO (when back compatibility will be broken  again)
-// Make Interference1DLatticeItem::P_DECAY_FUNCTION and
-// Interference2DLatticeItem::P_DECAY_FUNCTION rely on same constant
-
-InterferenceItem::~InterferenceItem() = default;
-
-DoubleDescriptor InterferenceItem::positionVariance() const
+InterferenceItem::InterferenceItem()
 {
-    DoubleDescriptor d(getItem(P_POSITION_VARIANCE), Unit::nanometerPower2);
-    d.tooltip = "Variance of the position in each dimension";
-    return d;
+    m_positionVariance.init("PositionVariance", "Variance of the position in each dimension", 0.0,
+                            Unit::nanometerPower2, "PositionVariance");
 }
 
-InterferenceItem::InterferenceItem(const QString& modelType) : SessionItem(modelType)
+DoubleDescriptor InterferenceItem::positionVariance() const
 {
-    addProperty(P_POSITION_VARIANCE, 0.0)
-        ->setToolTip("Variance of the position in each dimension (nm^2)");
+    return m_positionVariance;
 }
 
 // --------------------------------------------------------------------------------------------- //
 
-Interference1DLatticeItem::Interference1DLatticeItem() : InterferenceItem(M_TYPE)
+Interference1DLatticeItem::Interference1DLatticeItem()
 {
-    addProperty(P_LENGTH, 20.0 * Units::nm)->setToolTip("Lattice length in nanometers");
-    addProperty(P_ROTATION_ANGLE, 0.0)
-        ->setToolTip("Rotation of lattice with respect to x-axis of reference \n"
-                     "frame (beam direction) in degrees ");
-
-    GroupInfo info;
-    info.add<FTDecayFunction1DCauchyItem>();
-    info.add<FTDecayFunction1DGaussItem>();
-    info.add<FTDecayFunction1DTriangleItem>();
-    info.add<FTDecayFunction1DVoigtItem>();
-    info.setDefaultType<FTDecayFunction1DCauchyItem>();
-    addGroupProperty(P_DECAY_FUNCTION, info)
-        ->setToolTip("One-dimensional decay function (finite size effects)");
+    m_length.init("Length", "Lattice length", 20.0, Unit::nanometer, "Length");
+    m_rotationAngle.init(
+        "Xi", "Rotation of lattice with respect to x-axis of reference frame (beam direction)", 0.0,
+        Unit::degree, "xi");
+    m_decayFunction.init<FTDecayFunction1DItemCatalog>(
+        "Decay Function", "One-dimensional decay function (finite size effects)", "decay");
 }
 
 std::unique_ptr<IInterference> Interference1DLatticeItem::createInterference() const
 {
-    auto result = std::make_unique<Interference1DLattice>(
-        getItemValue(P_LENGTH).toDouble(),
-        Units::deg2rad(getItemValue(P_ROTATION_ANGLE).toDouble()));
-    auto* pdfItem = dynamic_cast<FTDecayFunction1DItem*>(
-        getGroupItem(Interference1DLatticeItem::P_DECAY_FUNCTION));
-    result->setDecayFunction(*pdfItem->createFTDecayFunction());
+    auto result =
+        std::make_unique<Interference1DLattice>(m_length, Units::deg2rad(m_rotationAngle));
+    result->setDecayFunction(*m_decayFunction->createFTDecayFunction());
     result->setPositionVariance(positionVariance());
     return std::unique_ptr<IInterference>(result.release());
 }
 
 DoubleDescriptor Interference1DLatticeItem::length() const
 {
-    DoubleDescriptor d(getItem(P_LENGTH), Unit::nanometer);
-    d.tooltip = "Lattice length";
-    return d;
+    return m_length;
 }
 
 DoubleDescriptor Interference1DLatticeItem::rotationAngle() const
 {
-    DoubleDescriptor d(getItem(P_ROTATION_ANGLE), Unit::degree);
-    d.tooltip = "Rotation of lattice with respect to x-axis of reference frame (beam direction)";
-    return d;
+    return m_rotationAngle;
+}
+
+void Interference1DLatticeItem::setDecayFunction(FTDecayFunction1DItem* p)
+{
+    m_decayFunction.set(p);
 }
 
 SelectionDescriptor<FTDecayFunction1DItem*> Interference1DLatticeItem::decayFunction() const
 {
-    return SelectionDescriptor<FTDecayFunction1DItem*>(item<GroupItem>(P_DECAY_FUNCTION));
+    return m_decayFunction;
 }
 
 // --------------------------------------------------------------------------------------------- //
 
 SelectionDescriptor<Lattice2DItem*> Interference2DAbstractLatticeItem::latticeType() const
 {
-    return SelectionDescriptor<Lattice2DItem*>(item<GroupItem>(P_LATTICE_TYPE));
+    return m_latticeType;
 }
 
-bool Interference2DAbstractLatticeItem::xiIntegration() const
+void Interference2DAbstractLatticeItem::setLatticeType(Lattice2DItem* p)
 {
-    return getItemValue(P_XI_INTEGRATION).toBool();
+    m_latticeType.set(p);
 }
 
-void Interference2DAbstractLatticeItem::setXiIntegration(bool xi_integration)
+bool Interference2DAbstractLatticeItem::xiIntegration() const
 {
-    setItemValue(P_XI_INTEGRATION, xi_integration);
+    return m_xiIntegration;
 }
 
-Interference2DAbstractLatticeItem::Interference2DAbstractLatticeItem(const QString& modelType,
-                                                                     bool xi_integration)
-    : InterferenceItem(modelType)
+void Interference2DAbstractLatticeItem::setXiIntegration(bool xiIntegration)
 {
-    GroupInfo info;
-    info.add<BasicLattice2DItem>();
-    info.add<SquareLattice2DItem>();
-    info.add<HexagonalLattice2DItem>();
-    info.setDefaultType<HexagonalLattice2DItem>();
-    addGroupProperty(P_LATTICE_TYPE, info)->setToolTip("Type of lattice");
+    m_xiIntegration = xiIntegration;
+}
 
-    addProperty(P_XI_INTEGRATION, xi_integration)
-        ->setToolTip("Enables/disables averaging over the lattice rotation angle.");
+Interference2DAbstractLatticeItem::Interference2DAbstractLatticeItem(bool xiIntegration)
+    : m_xiIntegration(xiIntegration)
+{
+    m_latticeType.init<Lattice2DItemCatalog>("Lattice type", "", "latticeType");
+    m_latticeType.set(new HexagonalLattice2DItem());
 }
 
 // --------------------------------------------------------------------------------------------- //
 
-Interference2DLatticeItem::Interference2DLatticeItem()
-    : Interference2DAbstractLatticeItem(M_TYPE, false)
+Interference2DLatticeItem::Interference2DLatticeItem() : Interference2DAbstractLatticeItem(false)
 {
-    GroupInfo info;
-    info.add<FTDecayFunction2DCauchyItem>();
-    info.add<FTDecayFunction2DGaussItem>();
-    info.add<FTDecayFunction2DVoigtItem>();
-    info.setDefaultType<FTDecayFunction2DCauchyItem>();
-    addGroupProperty(P_DECAY_FUNCTION, info)
-        ->setToolTip("Two-dimensional decay function (finite size effects)");
+    m_decayFunction.init<FTDecayFunction2DItemCatalog>(
+        "Decay Function", "Two-dimensional decay function (finite size effects)", "decay");
 }
 
 std::unique_ptr<IInterference> Interference2DLatticeItem::createInterference() const
@@ -141,8 +118,7 @@ std::unique_ptr<IInterference> Interference2DLatticeItem::createInterference() c
     std::unique_ptr<Interference2DLattice> result(
         new Interference2DLattice(*latticeItem->createLattice()));
 
-    auto& pdfItem = groupItem<FTDecayFunction2DItem>(P_DECAY_FUNCTION);
-    result->setDecayFunction(*pdfItem.createFTDecayFunction());
+    result->setDecayFunction(*m_decayFunction->createFTDecayFunction());
     result->setIntegrationOverXi(xiIntegration());
     result->setPositionVariance(positionVariance());
 
@@ -151,36 +127,24 @@ std::unique_ptr<IInterference> Interference2DLatticeItem::createInterference() c
 
 SelectionDescriptor<FTDecayFunction2DItem*> Interference2DLatticeItem::decayFunction() const
 {
-    return SelectionDescriptor<FTDecayFunction2DItem*>(item<GroupItem>(P_DECAY_FUNCTION));
+    return m_decayFunction;
 }
 
 // --------------------------------------------------------------------------------------------- //
 
 Interference2DParaCrystalItem::Interference2DParaCrystalItem()
-    : Interference2DAbstractLatticeItem(M_TYPE, true)
+    : Interference2DAbstractLatticeItem(true)
 {
-    latticeType().currentItem()->latticeRotationAngleItem()->setEnabled(false);
-
-    addProperty(P_DAMPING_LENGTH, 0.0)
-        ->setToolTip("The damping (coherence) length of the paracrystal in nanometers");
-
-    addProperty(P_DOMAIN_SIZE1, 20.0 * Units::micrometer)
-        ->setToolTip("Size of the coherent domain along the first basis vector in nanometers");
-    addProperty(P_DOMAIN_SIZE2, 20.0 * Units::micrometer)
-        ->setToolTip("Size of the coherent domain along the second basis vector in nanometers");
-
-    GroupInfo info;
-    info.add<FTDistribution2DCauchyItem>();
-    info.add<FTDistribution2DGaussItem>();
-    info.add<FTDistribution2DGateItem>();
-    info.add<FTDistribution2DConeItem>();
-    info.add<FTDistribution2DVoigtItem>();
-    info.setDefaultType<FTDistribution2DCauchyItem>();
-
-    addGroupProperty(P_PDF1, info)
-        ->setToolTip("Probability distribution in first lattice direction");
-    addGroupProperty(P_PDF2, info)
-        ->setToolTip("Probability distribution in second lattice direction");
+    m_dampingLength.init("Damping length", "The damping (coherence) length of the paracrystal", 0.0,
+                         Unit::nanometer, "dampingLen");
+    m_domainSize1.init("Domain size 1", "Size of the coherent domain along the first basis vector",
+                       20000.0, Unit::nanometer, "size1");
+    m_domainSize2.init("Domain size 2", "Size of the coherent domain along the second basis vector",
+                       20000.0, Unit::nanometer, "size2");
+    m_pdf1.init<FTDistribution2DItemCatalog>(
+        "PDF 1", "Probability distribution in first lattice direction", "pdf1");
+    m_pdf2.init<FTDistribution2DItemCatalog>(
+        "PDF 2", "Probability distribution in second lattice direction", "pdf2");
 }
 
 std::unique_ptr<IInterference> Interference2DParaCrystalItem::createInterference() const
@@ -190,84 +154,83 @@ std::unique_ptr<IInterference> Interference2DParaCrystalItem::createInterference
     std::unique_ptr<Interference2DParaCrystal> result(
         new Interference2DParaCrystal(*latticeItem->createLattice(), 0, 0, 0));
 
-    result->setDampingLength(getItemValue(P_DAMPING_LENGTH).toDouble());
-    result->setDomainSizes(getItemValue(P_DOMAIN_SIZE1).toDouble(),
-                           getItemValue(P_DOMAIN_SIZE2).toDouble());
+    result->setDampingLength(m_dampingLength);
+    result->setDomainSizes(m_domainSize1, m_domainSize2);
     result->setIntegrationOverXi(xiIntegration());
-
-    auto& pdf1Item = groupItem<FTDistribution2DItem>(Interference2DParaCrystalItem::P_PDF1);
-    auto& pdf2Item = groupItem<FTDistribution2DItem>(Interference2DParaCrystalItem::P_PDF2);
-    result->setProbabilityDistributions(*pdf1Item.createFTDistribution(),
-                                        *pdf2Item.createFTDistribution());
-
+    result->setProbabilityDistributions(*m_pdf1->createFTDistribution(),
+                                        *m_pdf2->createFTDistribution());
     result->setPositionVariance(positionVariance());
     return std::unique_ptr<IInterference>(result.release());
 }
 
 DoubleDescriptor Interference2DParaCrystalItem::dampingLength() const
 {
-    DoubleDescriptor d(getItem(P_DAMPING_LENGTH), Unit::nanometer);
-    d.tooltip = "The damping (coherence) length of the paracrystal";
-    return d;
+    return m_dampingLength;
 }
 
-void Interference2DParaCrystalItem::setDampingLength(const double damping_length)
+void Interference2DParaCrystalItem::setDampingLength(double dampingLength)
 {
-    setItemValue(P_DAMPING_LENGTH, damping_length);
+    m_dampingLength.set(dampingLength);
 }
 
 DoubleDescriptor Interference2DParaCrystalItem::domainSize1() const
 {
-    DoubleDescriptor d(getItem(P_DOMAIN_SIZE1), Unit::nanometer);
-    d.tooltip = "Size of the coherent domain along the first basis vector";
-    return d;
+    return m_domainSize1;
 }
 
-void Interference2DParaCrystalItem::setDomainSize1(const double domain_size1)
+void Interference2DParaCrystalItem::setDomainSize1(const double size)
 {
-    setItemValue(P_DOMAIN_SIZE1, domain_size1);
+    m_domainSize1.set(size);
 }
 
 DoubleDescriptor Interference2DParaCrystalItem::domainSize2() const
 {
-    DoubleDescriptor d(getItem(P_DOMAIN_SIZE2), Unit::nanometer);
-    d.tooltip = "Size of the coherent domain along the second basis vector";
-    return d;
+    return m_domainSize2;
 }
 
-void Interference2DParaCrystalItem::setDomainSize2(const double domain_size2)
+void Interference2DParaCrystalItem::setDomainSize2(const double size)
 {
-    setItemValue(P_DOMAIN_SIZE2, domain_size2);
+    m_domainSize2.set(size);
 }
 
 SelectionDescriptor<FTDistribution2DItem*>
 Interference2DParaCrystalItem::probabilityDistribution1() const
 {
-    return SelectionDescriptor<FTDistribution2DItem*>(item<GroupItem>(P_PDF1));
+    return m_pdf1;
+}
+
+void Interference2DParaCrystalItem::setPDF1Type(FTDistribution2DItem* p)
+{
+    m_pdf1.set(p);
 }
 
 SelectionDescriptor<FTDistribution2DItem*>
 Interference2DParaCrystalItem::probabilityDistribution2() const
 {
-    return SelectionDescriptor<FTDistribution2DItem*>(item<GroupItem>(P_PDF2));
+    return m_pdf2;
+}
+
+void Interference2DParaCrystalItem::setPDF2Type(FTDistribution2DItem* p)
+{
+    m_pdf2.set(p);
 }
 
 // --------------------------------------------------------------------------------------------- //
 
 InterferenceFinite2DLatticeItem::InterferenceFinite2DLatticeItem()
-    : Interference2DAbstractLatticeItem(M_TYPE, false)
+    : Interference2DAbstractLatticeItem(false)
 {
-    addProperty(P_DOMAIN_SIZE_1, 100u)->setToolTip("Domain size 1 in number of unit cells");
-    addProperty(P_DOMAIN_SIZE_2, 100u)->setToolTip("Domain size 2 in number of unit cells");
+    m_domainSize1.init("Domain size 1", "Domain size 1 in number of unit cells", 100,
+                       Unit::unitless, "size1");
+    m_domainSize2.init("Domain size 2", "Domain size 2 in number of unit cells", 100,
+                       Unit::unitless, "size2");
 }
 
 std::unique_ptr<IInterference> InterferenceFinite2DLatticeItem::createInterference() const
 {
     Lattice2DItem* latticeItem = latticeType().currentItem();
-    auto size_1 = getItemValue(P_DOMAIN_SIZE_1).toUInt();
-    auto size_2 = getItemValue(P_DOMAIN_SIZE_2).toUInt();
-    std::unique_ptr<InterferenceFinite2DLattice> result(
-        new InterferenceFinite2DLattice(*latticeItem->createLattice(), size_1, size_2));
+    std::unique_ptr<InterferenceFinite2DLattice> result(new InterferenceFinite2DLattice(
+        *latticeItem->createLattice(), m_domainSize1, m_domainSize2));
 
     result->setIntegrationOverXi(xiIntegration());
     result->setPositionVariance(positionVariance());
@@ -277,122 +240,104 @@ std::unique_ptr<IInterference> InterferenceFinite2DLatticeItem::createInterferen
 
 UIntDescriptor InterferenceFinite2DLatticeItem::domainSize1()
 {
-    return UIntDescriptor(getItem(P_DOMAIN_SIZE_1), Unit::unitless);
+    return m_domainSize1;
 }
 
-void InterferenceFinite2DLatticeItem::setDomainSize1(const unsigned int domain_size1)
+void InterferenceFinite2DLatticeItem::setDomainSize1(const unsigned int size)
 {
-    setItemValue(P_DOMAIN_SIZE_1, domain_size1);
+    m_domainSize1.set(size);
 }
 
 UIntDescriptor InterferenceFinite2DLatticeItem::domainSize2()
 {
-    return UIntDescriptor(getItem(P_DOMAIN_SIZE_2), Unit::unitless);
+    return m_domainSize2;
 }
 
-void InterferenceFinite2DLatticeItem::setDomainSize2(const unsigned int domain_size2)
+void InterferenceFinite2DLatticeItem::setDomainSize2(const unsigned int size)
 {
-    setItemValue(P_DOMAIN_SIZE_2, domain_size2);
+    m_domainSize2.set(size);
 }
 
 // --------------------------------------------------------------------------------------------- //
 
-InterferenceHardDiskItem::InterferenceHardDiskItem() : InterferenceItem(M_TYPE)
+InterferenceHardDiskItem::InterferenceHardDiskItem()
 {
-    addProperty(P_RADIUS, 5.0 * Units::nm)->setToolTip("Hard disk radius in nanometers");
-    addProperty(P_DENSITY, 0.002)->setToolTip("Particle density in particles per square nanometer");
+    m_radius.init("Radius", "Hard disk radius", 5.0, Unit::nanometer, "radius");
+    m_density.init("Total particle density", "Particle density in particles per area", 0.002,
+                   Unit::nanometerPowerMinus2, "density");
 }
 
 std::unique_ptr<IInterference> InterferenceHardDiskItem::createInterference() const
 {
-    auto result = std::make_unique<InterferenceHardDisk>(getItemValue(P_RADIUS).toDouble(),
-                                                         getItemValue(P_DENSITY).toDouble());
+    auto result = std::make_unique<InterferenceHardDisk>(m_radius, m_density);
     result->setPositionVariance(positionVariance());
     return std::unique_ptr<IInterference>(result.release());
 }
 
 DoubleDescriptor InterferenceHardDiskItem::density() const
 {
-    DoubleDescriptor d(getItem(P_DENSITY), Unit::nanometerPowerMinus2);
-    d.tooltip = "Particle density in particles per area";
-    return d;
+    return m_density;
 }
 
 DoubleDescriptor InterferenceHardDiskItem::radius() const
 {
-    DoubleDescriptor d(getItem(P_RADIUS), Unit::nanometer);
-    d.tooltip = "Hard disk radius";
-    return d;
+    return m_radius;
 }
 
 // --------------------------------------------------------------------------------------------- //
 
-InterferenceRadialParaCrystalItem::InterferenceRadialParaCrystalItem() : InterferenceItem(M_TYPE)
-{
-    addProperty(P_PEAK_DISTANCE, 20.0 * Units::nm)
-        ->setToolTip("Average distance to the next neighbor in nanometers");
-    addProperty(P_DAMPING_LENGTH, 1000.0 * Units::nm)
-        ->setToolTip("The damping (coherence) length of the paracrystal "
-                     "in nanometers");
-    addProperty(P_DOMAIN_SIZE, 0.0)
-        ->setToolTip("Size of coherence domain along the lattice main axis "
-                     "in nanometers");
-    addProperty(P_KAPPA, 0.0)
-        ->setToolTip("Size spacing coupling parameter of the Size Spacing "
-                     "Correlation Approximation");
-
-    GroupInfo info;
-    info.add<FTDistribution1DCauchyItem>();
-    info.add<FTDistribution1DGaussItem>();
-    info.add<FTDistribution1DGateItem>();
-    info.add<FTDistribution1DTriangleItem>();
-    info.add<FTDistribution1DCosineItem>();
-    info.add<FTDistribution1DVoigtItem>();
-    info.setDefaultType<FTDistribution1DCauchyItem>();
-    addGroupProperty(P_PDF, info)->setToolTip("One-dimensional probability distribution");
+InterferenceRadialParaCrystalItem::InterferenceRadialParaCrystalItem()
+{
+    m_peakDistance.init("Peak distance", "Average distance to the next neighbor", 20.0,
+                        Unit::nanometer, "peak");
+    m_dampingLength.init("Damping length", "The damping (coherence) length of the paracrystal",
+                         1000.0, Unit::nanometer, "dampingLen");
+    m_domainSize.init("Domain size", "Size of coherence domain along the lattice main axis", 0.0,
+                      Unit::nanometer, "size");
+    m_kappa.init("SizeSpaceCoupling",
+                 "Size spacing coupling parameter of the Size Spacing Correlation Approximation",
+                 0.0, Unit::unitless, "kappa");
+    m_pdf.init<FTDistribution1DItemCatalog>("PDF", "One-dimensional probability distribution",
+                                            "pdf");
 }
 
 std::unique_ptr<IInterference> InterferenceRadialParaCrystalItem::createInterference() const
 {
-    auto result = std::make_unique<InterferenceRadialParaCrystal>(
-        getItemValue(P_PEAK_DISTANCE).toDouble(), getItemValue(P_DAMPING_LENGTH).toDouble());
-    result->setDomainSize(getItemValue(P_DOMAIN_SIZE).toDouble());
-    result->setKappa(getItemValue(P_KAPPA).toDouble());
-
-    auto& pdfItem = groupItem<FTDistribution1DItem>(P_PDF);
-    result->setProbabilityDistribution(*pdfItem.createFTDistribution());
+    auto result = std::make_unique<InterferenceRadialParaCrystal>(m_peakDistance, m_dampingLength);
+    result->setDomainSize(m_domainSize);
+    result->setKappa(m_kappa);
+    result->setProbabilityDistribution(*m_pdf->createFTDistribution());
     result->setPositionVariance(positionVariance());
     return std::unique_ptr<IInterference>(result.release());
 }
 
 DoubleDescriptor InterferenceRadialParaCrystalItem::peakDistance() const
 {
-    DoubleDescriptor d(getItem(P_PEAK_DISTANCE), Unit::nanometer);
-    d.tooltip = "Average distance to the next neighbor";
-    return d;
+    return m_peakDistance;
 }
 
 DoubleDescriptor InterferenceRadialParaCrystalItem::dampingLength() const
 {
-    DoubleDescriptor d(getItem(P_DAMPING_LENGTH), Unit::nanometer);
-    d.tooltip = "The damping (coherence) length of the paracrystal";
-    return d;
+    return m_dampingLength;
 }
 
 DoubleDescriptor InterferenceRadialParaCrystalItem::domainSize() const
 {
-    DoubleDescriptor d(getItem(P_DOMAIN_SIZE), Unit::nanometer);
-    d.tooltip = "Size of coherence domain along the lattice main axis";
-    return d;
+    return m_domainSize;
 }
 
 DoubleDescriptor InterferenceRadialParaCrystalItem::kappa() const
 {
-    return DoubleDescriptor(getItem(P_KAPPA), Unit::unitless);
+    return m_kappa;
 }
 
 SelectionDescriptor<FTDistribution1DItem*>
 InterferenceRadialParaCrystalItem::probabilityDistribution() const
 {
-    return SelectionDescriptor<FTDistribution1DItem*>(item<GroupItem>(P_PDF));
+    return m_pdf;
+}
+
+void InterferenceRadialParaCrystalItem::setPDFType(FTDistribution1DItem* p)
+{
+    m_pdf.set(p);
 }
diff --git a/GUI/Model/Sample/InterferenceItems.h b/GUI/Model/Sample/InterferenceItems.h
index d62a7721718ff4f8ec452b4ab177df7170f14ebf..63408ba65daf042ea3decae445a349b4b1afd288 100644
--- a/GUI/Model/Sample/InterferenceItems.h
+++ b/GUI/Model/Sample/InterferenceItems.h
@@ -7,7 +7,7 @@
 //!
 //! @homepage  http://www.bornagainproject.org
 //! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @copyright Forschungszentrum Jülich GmbH 2021
 //! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
 //
 //  ************************************************************************************************
@@ -15,8 +15,9 @@
 #ifndef BORNAGAIN_GUI_MODEL_SAMPLE_INTERFERENCEITEMS_H
 #define BORNAGAIN_GUI_MODEL_SAMPLE_INTERFERENCEITEMS_H
 
-#include "GUI/Model/Group/SelectionDescriptor.h"
-#include "GUI/Model/Session/SessionItem.h"
+#include "GUI/Model/Types/DoubleProperty.h"
+#include "GUI/Model/Types/SelectionProperty.h"
+#include "GUI/Model/Types/UIntProperty.h"
 
 class FTDecayFunction1DItem;
 class FTDecayFunction2DItem;
@@ -24,109 +25,95 @@ class FTDistribution1DItem;
 class FTDistribution2DItem;
 class IInterference;
 class Lattice2DItem;
-class DoubleDescriptor;
-class UIntDescriptor;
-
-class InterferenceItem : public SessionItem {
-private:
-    static constexpr auto P_POSITION_VARIANCE{"PositionVariance"};
 
+class InterferenceItem {
 public:
-    ~InterferenceItem() override;
+    virtual ~InterferenceItem() = default;
     virtual std::unique_ptr<IInterference> createInterference() const = 0;
 
     DoubleDescriptor positionVariance() const;
 
 protected:
-    explicit InterferenceItem(const QString& modelType);
-};
+    InterferenceItem();
 
-class Interference1DLatticeItem : public InterferenceItem {
 private:
-    static constexpr auto P_LENGTH{"Length"};
-    static constexpr auto P_ROTATION_ANGLE{"Xi"};
-    static constexpr auto P_DECAY_FUNCTION{"Decay Function"};
+    DoubleProperty m_positionVariance;
+};
 
+class Interference1DLatticeItem : public InterferenceItem {
 public:
-    static constexpr auto M_TYPE{"Interference1DLattice"};
-
     Interference1DLatticeItem();
+
     std::unique_ptr<IInterference> createInterference() const override;
 
     DoubleDescriptor length() const;
     DoubleDescriptor rotationAngle() const;
 
-    template <typename T> T* setDecayFunctionType();
+    void setDecayFunction(FTDecayFunction1DItem* p);
     SelectionDescriptor<FTDecayFunction1DItem*> decayFunction() const;
-};
 
-class Interference2DAbstractLatticeItem : public InterferenceItem {
 private:
-    static constexpr auto P_LATTICE_TYPE{"LatticeType"};
-    static constexpr auto P_XI_INTEGRATION{"Integration_over_xi"};
+    DoubleProperty m_length;
+    DoubleProperty m_rotationAngle;
+    SelectionProperty<FTDecayFunction1DItem*> m_decayFunction;
+};
 
+class Interference2DAbstractLatticeItem : public InterferenceItem {
 public:
     SelectionDescriptor<Lattice2DItem*> latticeType() const;
-    template <typename T> T* setLatticeType();
+    void setLatticeType(Lattice2DItem* p);
 
     bool xiIntegration() const;
-    void setXiIntegration(bool xi_integration);
+    void setXiIntegration(bool xiIntegration);
 
 protected:
-    explicit Interference2DAbstractLatticeItem(const QString& modelType, bool xi_integration);
+    explicit Interference2DAbstractLatticeItem(bool xiIntegration);
+
+    bool m_xiIntegration; // #baMigration serialize
+    SelectionProperty<Lattice2DItem*> m_latticeType;
 };
 
 class Interference2DLatticeItem : public Interference2DAbstractLatticeItem {
-private:
-    static constexpr auto P_DECAY_FUNCTION{"Decay Function"};
-
 public:
-    static constexpr auto M_TYPE{"Interference2DLattice"};
-
     Interference2DLatticeItem();
     std::unique_ptr<IInterference> createInterference() const override;
 
     template <typename T> T* setDecayFunctionType();
     SelectionDescriptor<FTDecayFunction2DItem*> decayFunction() const;
+
+protected:
+    SelectionProperty<FTDecayFunction2DItem*> m_decayFunction;
 };
 
 class Interference2DParaCrystalItem : public Interference2DAbstractLatticeItem {
-private:
-    static constexpr auto P_DAMPING_LENGTH{"DampingLength"};
-    static constexpr auto P_DOMAIN_SIZE1{"DomainSize1"};
-    static constexpr auto P_DOMAIN_SIZE2{"DomainSize2"};
-    static constexpr auto P_PDF1{"PDF #1"};
-    static constexpr auto P_PDF2{"PDF #2"};
-
 public:
-    static constexpr auto M_TYPE{"Interference2DParaCrystal"};
-
     Interference2DParaCrystalItem();
     std::unique_ptr<IInterference> createInterference() const override;
 
     DoubleDescriptor dampingLength() const;
-    void setDampingLength(double damping_length);
+    void setDampingLength(double dampingLength);
 
     DoubleDescriptor domainSize1() const;
-    void setDomainSize1(double domain_size1);
+    void setDomainSize1(double size);
     DoubleDescriptor domainSize2() const;
-    void setDomainSize2(double domain_size2);
+    void setDomainSize2(double size);
 
     SelectionDescriptor<FTDistribution2DItem*> probabilityDistribution1() const;
-    template <typename T> T* setPDF1Type();
+    void setPDF1Type(FTDistribution2DItem* p);
 
     SelectionDescriptor<FTDistribution2DItem*> probabilityDistribution2() const;
-    template <typename T> T* setPDF2Type();
-};
+    void setPDF2Type(FTDistribution2DItem* p);
 
-class InterferenceFinite2DLatticeItem : public Interference2DAbstractLatticeItem {
 private:
-    static constexpr auto P_DOMAIN_SIZE_1{"Domain_size_1"};
-    static constexpr auto P_DOMAIN_SIZE_2{"Domain_size_2"};
+    DoubleProperty m_dampingLength;
+    DoubleProperty m_domainSize1;
+    DoubleProperty m_domainSize2;
+    SelectionProperty<FTDistribution2DItem*> m_pdf1;
+    SelectionProperty<FTDistribution2DItem*> m_pdf2;
+};
 
+class InterferenceFinite2DLatticeItem : public Interference2DAbstractLatticeItem {
 public:
-    static constexpr auto M_TYPE{"InterferenceFinite2DLattice"};
-
     InterferenceFinite2DLatticeItem();
     std::unique_ptr<IInterference> createInterference() const override;
 
@@ -134,34 +121,27 @@ public:
     void setDomainSize1(unsigned int domain_size1);
     UIntDescriptor domainSize2();
     void setDomainSize2(unsigned int domain_size2);
-};
 
-class InterferenceHardDiskItem : public InterferenceItem {
 private:
-    static constexpr auto P_RADIUS{"Radius"};
-    static constexpr auto P_DENSITY{"TotalParticleDensity"};
+    UIntProperty m_domainSize1;
+    UIntProperty m_domainSize2;
+};
 
+class InterferenceHardDiskItem : public InterferenceItem {
 public:
-    static constexpr auto M_TYPE{"InterferenceHardDisk"};
-
     InterferenceHardDiskItem();
     std::unique_ptr<IInterference> createInterference() const override;
 
     DoubleDescriptor radius() const;
     DoubleDescriptor density() const;
-};
 
-class InterferenceRadialParaCrystalItem : public InterferenceItem {
 private:
-    static constexpr auto P_PEAK_DISTANCE{"PeakDistance"};
-    static constexpr auto P_DAMPING_LENGTH{"DampingLength"};
-    static constexpr auto P_DOMAIN_SIZE{"DomainSize"};
-    static constexpr auto P_KAPPA{"SizeSpaceCoupling"};
-    static constexpr auto P_PDF{"PDF"};
+    DoubleProperty m_radius;
+    DoubleProperty m_density;
+};
 
+class InterferenceRadialParaCrystalItem : public InterferenceItem {
 public:
-    static constexpr auto M_TYPE{"InterferenceRadialParaCrystal"};
-
     InterferenceRadialParaCrystalItem();
     std::unique_ptr<IInterference> createInterference() const override;
 
@@ -170,55 +150,14 @@ public:
     DoubleDescriptor domainSize() const;
     DoubleDescriptor kappa() const;
     SelectionDescriptor<FTDistribution1DItem*> probabilityDistribution() const;
-    template <typename T> T* setPDFType();
-};
-
-template <typename T> T* Interference1DLatticeItem::setDecayFunctionType()
-{
-    static_assert(std::is_base_of<FTDecayFunction1DItem, T>::value,
-                  "Class must be derived from FTDecayFunction1DItem");
+    void setPDFType(FTDistribution1DItem* p);
 
-    return setGroupPropertyType<T>(P_DECAY_FUNCTION);
-}
-
-template <typename T> T* Interference2DAbstractLatticeItem::setLatticeType()
-{
-    static_assert(std::is_base_of<Lattice2DItem, T>::value,
-                  "Class must be derived from Lattice2DItem");
-
-    return setGroupPropertyType<T>(P_LATTICE_TYPE);
-}
-
-template <typename T> T* Interference2DLatticeItem::setDecayFunctionType()
-{
-    static_assert(std::is_base_of<FTDecayFunction2DItem, T>::value,
-                  "Class must be derived from FTDecayFunction2DItem");
-
-    return setGroupPropertyType<T>(P_DECAY_FUNCTION);
-}
-
-template <typename T> T* Interference2DParaCrystalItem::setPDF1Type()
-{
-    static_assert(std::is_base_of<FTDistribution2DItem, T>::value,
-                  "Class must be derived from FTDistribution2DItem");
-
-    return setGroupPropertyType<T>(P_PDF1);
-}
-
-template <typename T> T* Interference2DParaCrystalItem::setPDF2Type()
-{
-    static_assert(std::is_base_of<FTDistribution2DItem, T>::value,
-                  "Class must be derived from FTDistribution2DItem");
-
-    return setGroupPropertyType<T>(P_PDF2);
-}
-
-template <typename T> T* InterferenceRadialParaCrystalItem::setPDFType()
-{
-    static_assert(std::is_base_of<FTDistribution1DItem, T>::value,
-                  "Class must be derived from FTDistribution1DItem");
-
-    return setGroupPropertyType<T>(P_PDF);
-}
+private:
+    DoubleProperty m_peakDistance;
+    DoubleProperty m_dampingLength;
+    DoubleProperty m_domainSize;
+    DoubleProperty m_kappa;
+    SelectionProperty<FTDistribution1DItem*> m_pdf;
+};
 
 #endif // BORNAGAIN_GUI_MODEL_SAMPLE_INTERFERENCEITEMS_H