diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
index 49240394e26010b00e37c4e02b04cb46783a07bc..db00e67a35782d17679a1367f035d9d008fe8cc6 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
@@ -2410,9 +2410,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
         checkSession(sessionToken);
 
         IDeletionDAO deletionDAO = getDAOFactory().getDeletionDAO();
-        // NOTE:
-        // - we can't do bulk deletions to preserve original reason
-        // - we keep findTrashed... methods with collections as arguments for future use
+        // NOTE: we can't do bulk deletions to preserve original reasons
         for (TechId deletionId : deletionIds)
         {
             DeletionPE deletion = deletionDAO.getByTechId(deletionId);
@@ -2423,8 +2421,15 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
             List<String> trashedDataSets = deletionDAO.findTrashedDataSetCodes(singletonList);
             deleteDataSets(sessionToken, trashedDataSets, deletionReason, deletionType);
 
-            List<TechId> trashedSamples = deletionDAO.findTrashedSampleIds(singletonList);
-            deleteSamples(sessionToken, trashedSamples, deletionReason, deletionType);
+            // we need to first delete components and then containers not to break constraints
+            List<TechId> trashedComponentSamples =
+                    deletionDAO.findTrashedComponentSampleIds(singletonList);
+            deleteSamples(sessionToken, trashedComponentSamples, deletionReason, deletionType);
+            List<TechId> trashedNonComponentSamples =
+                    deletionDAO.findTrashedNonComponentSampleIds(singletonList);
+            deleteSamples(sessionToken, trashedNonComponentSamples, deletionReason, deletionType);
+            // List<TechId> trashedSamples = deletionDAO.findTrashedSampleIds(singletonList);
+            // deleteSamples(sessionToken, trashedSamples, deletionReason, deletionType);
 
             List<TechId> trashedExperiments = deletionDAO.findTrashedExperimentIds(singletonList);
             deleteExperiments(sessionToken, trashedExperiments, deletionReason, deletionType);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DeletionDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DeletionDAO.java
index bced950f11bb93af2fa0f637df1e4d1bb3211b75..e0c2e5085f1ec3615d874683ddbd00035c85c990 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DeletionDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DeletionDAO.java
@@ -24,6 +24,7 @@ import org.apache.log4j.Logger;
 import org.hibernate.HibernateException;
 import org.hibernate.Session;
 import org.hibernate.SessionFactory;
+import org.hibernate.criterion.Criterion;
 import org.hibernate.criterion.DetachedCriteria;
 import org.hibernate.criterion.Projections;
 import org.hibernate.criterion.Restrictions;
@@ -52,6 +53,10 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind;
 final class DeletionDAO extends AbstractGenericEntityDAO<DeletionPE> implements IDeletionDAO
 {
 
+    private static final String DELETION_ID = "deletion.id";
+
+    private static final String CONTAINER_ID = "containerId";
+
     /**
      * This logger does not output any SQL statement. If you want to do so, you had better set an
      * appropriate debugging level for class {@link JdbcAccessor}. </p>
@@ -127,6 +132,18 @@ final class DeletionDAO extends AbstractGenericEntityDAO<DeletionPE> implements
         return findTrashedEntityIds(deletionIds, EntityKind.SAMPLE);
     }
 
+    public List<TechId> findTrashedNonComponentSampleIds(final List<TechId> deletionIds)
+    {
+        return findTrashedEntityIds(deletionIds, EntityKind.SAMPLE,
+                Restrictions.isNull(CONTAINER_ID));
+    }
+
+    public List<TechId> findTrashedComponentSampleIds(final List<TechId> deletionIds)
+    {
+        return findTrashedEntityIds(deletionIds, EntityKind.SAMPLE,
+                Restrictions.isNotNull(CONTAINER_ID));
+    }
+
     public List<TechId> findTrashedExperimentIds(final List<TechId> deletionIds)
     {
         return findTrashedEntityIds(deletionIds, EntityKind.EXPERIMENT);
@@ -138,7 +155,7 @@ final class DeletionDAO extends AbstractGenericEntityDAO<DeletionPE> implements
                 DetachedCriteria.forClass(EntityKind.DATA_SET.getDeletedEntityClass());
         final List<Long> longIds = TechId.asLongs(deletionIds);
         criteria.setProjection(Projections.property("code"));
-        criteria.add(Restrictions.in("deletion.id", longIds));
+        criteria.add(Restrictions.in(DELETION_ID, longIds));
         final List<String> results = cast(getHibernateTemplate().findByCriteria(criteria));
         operationLog.info(String.format("found %s trashed %s(s)", results.size(),
                 EntityKind.DATA_SET.name()));
@@ -146,13 +163,17 @@ final class DeletionDAO extends AbstractGenericEntityDAO<DeletionPE> implements
     }
 
     private List<TechId> findTrashedEntityIds(final List<TechId> deletionIds,
-            final EntityKind entityKind)
+            final EntityKind entityKind, Criterion... additionalCriteria)
     {
         final DetachedCriteria criteria =
                 DetachedCriteria.forClass(entityKind.getDeletedEntityClass());
         final List<Long> longIds = TechId.asLongs(deletionIds);
         criteria.setProjection(Projections.id());
-        criteria.add(Restrictions.in("deletion.id", longIds));
+        criteria.add(Restrictions.in(DELETION_ID, longIds));
+        for (Criterion criterion : additionalCriteria)
+        {
+            criteria.add(criterion);
+        }
         final List<Long> results = cast(getHibernateTemplate().findByCriteria(criteria));
         operationLog
                 .info(String.format("found %s trashed %s(s)", results.size(), entityKind.name()));
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DeletedSamplePE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DeletedSamplePE.java
index 694cdedc7bf03ab779cf40d13bedba87062263b0..18f2ebf0332599fe31db941e7029c191dd111023 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DeletedSamplePE.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DeletedSamplePE.java
@@ -16,6 +16,7 @@
 
 package ch.systemsx.cisd.openbis.generic.shared.dto;
 
+import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
@@ -46,6 +47,8 @@ public class DeletedSamplePE extends AbstractDeletedEntityPE
 
     private transient Long id;
 
+    private Long containerId;
+
     @Id
     @SequenceGenerator(name = SequenceNames.SAMPLE_SEQUENCE, sequenceName = SequenceNames.SAMPLE_SEQUENCE, allocationSize = 1)
     @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = SequenceNames.SAMPLE_SEQUENCE)
@@ -60,6 +63,17 @@ public class DeletedSamplePE extends AbstractDeletedEntityPE
         this.id = id;
     }
 
+    @Column(name = ColumnNames.PART_OF_SAMPLE_COLUMN, nullable = false, insertable = false, updatable = false)
+    public Long getContainerId()
+    {
+        return containerId;
+    }
+
+    public void setContainerId(final Long containerId)
+    {
+        this.containerId = containerId;
+    }
+
     //
     // Object
     //