diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAO.java
index 721b9cf491ec60f7d25072a6b9c1ac486e32c790..2c6e7f8067616c9568e0d6a5ad9ceb290377d58f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAO.java
@@ -387,6 +387,12 @@ public class SampleDAO extends AbstractGenericEntityWithPropertiesDAO<SamplePE>
                 "SELECT perm_id FROM " + TableNames.SAMPLES_TABLE + " WHERE id = :sId";
         final String sqlDeleteProperties =
                 "DELETE FROM " + TableNames.SAMPLE_PROPERTIES_TABLE + " WHERE samp_id = :sId";
+        final String sqlAttachmentContentIds =
+                "SELECT exac_id FROM " + TableNames.ATTACHMENTS_TABLE + " WHERE samp_id = :sId";
+        final String sqlDeleteAttachmentContents =
+                "DELETE FROM " + TableNames.ATTACHMENT_CONTENT_TABLE + " WHERE id in (:aIds)";
+        final String sqlDeleteAttachments =
+                "DELETE FROM " + TableNames.ATTACHMENTS_TABLE + " WHERE samp_id = :sId";
         final String sqlDeleteSample =
                 "DELETE FROM " + TableNames.SAMPLES_TABLE + " WHERE id = :sId";
         final String sqlInsertEvent =
@@ -404,6 +410,12 @@ public class SampleDAO extends AbstractGenericEntityWithPropertiesDAO<SamplePE>
                             session.createSQLQuery(sqlDeleteProperties);
                     final SQLQuery sqlQueryDeleteSample = session.createSQLQuery(sqlDeleteSample);
                     final SQLQuery sqlQueryInsertEvent = session.createSQLQuery(sqlInsertEvent);
+                    final SQLQuery sqlQueryAttachmentContentIds =
+                            session.createSQLQuery(sqlAttachmentContentIds);
+                    final SQLQuery sqlQueryDeleteAttachments =
+                            session.createSQLQuery(sqlDeleteAttachments);
+                    final SQLQuery sqlQueryDeleteAttachmentContents =
+                            session.createSQLQuery(sqlDeleteAttachmentContents);
                     sqlQueryInsertEvent.setParameter("eventType", EventType.DELETION.name());
                     sqlQueryInsertEvent.setParameter("reason", reason);
                     sqlQueryInsertEvent.setParameter("registratorId", registrator.getId());
@@ -418,6 +430,18 @@ public class SampleDAO extends AbstractGenericEntityWithPropertiesDAO<SamplePE>
                             // delete properties
                             sqlQueryDeleteProperties.setParameter("sId", techId.getId());
                             sqlQueryDeleteProperties.executeUpdate();
+                            // delete attachments
+                            sqlQueryAttachmentContentIds.setParameter("sId", techId.getId());
+                            List<Long> attachmentContentIds =
+                                    cast(sqlQueryAttachmentContentIds.list());
+                            if (attachmentContentIds.size() > 0)
+                            {
+                                sqlQueryDeleteAttachments.setParameter("sId", techId.getId());
+                                sqlQueryDeleteAttachments.executeUpdate();
+                                sqlQueryDeleteAttachmentContents.setParameterList("aIds",
+                                        attachmentContentIds);
+                                sqlQueryDeleteAttachmentContents.executeUpdate();
+                            }
                             // delete sample
                             sqlQueryDeleteSample.setParameter("sId", techId.getId());
                             sqlQueryDeleteSample.executeUpdate();
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/AttachmentContentPE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/AttachmentContentPE.java
index e3f00e7c308f2e21fdff3c2e0d74268bb5a7cec7..8edfc7430ad0e529a122106d1bab26a9ab809f09 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/AttachmentContentPE.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/AttachmentContentPE.java
@@ -30,6 +30,7 @@ import org.hibernate.annotations.Type;
 import org.hibernate.validator.NotNull;
 
 import ch.systemsx.cisd.openbis.generic.shared.IServer;
+import ch.systemsx.cisd.openbis.generic.shared.basic.IIdHolder;
 
 /**
  * An attachment content <i>Persistent Entity</i>.
@@ -38,7 +39,7 @@ import ch.systemsx.cisd.openbis.generic.shared.IServer;
  */
 @Entity
 @Table(name = TableNames.ATTACHMENT_CONTENT_TABLE)
-public class AttachmentContentPE implements Serializable
+public class AttachmentContentPE implements IIdHolder, Serializable
 {
     private static final long serialVersionUID = IServer.VERSION;
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/ExperimentPE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/ExperimentPE.java
index 52f64fcc000ac4a799d51be9f0b408b326a0546e..f3f595074c48426bb8536463c2d9ab3e03dab558 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/ExperimentPE.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/ExperimentPE.java
@@ -314,7 +314,8 @@ public class ExperimentPE extends AttachmentHolderPE implements
     }
 
     @Override
-    @OneToMany(fetch = FetchType.LAZY, mappedBy = "experimentParentInternal")
+    @OneToMany(fetch = FetchType.LAZY, mappedBy = "experimentParentInternal", cascade = CascadeType.ALL)
+    @Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
     @IndexedEmbedded(prefix = SearchFieldConstants.PREFIX_ATTACHMENT)
     @Fetch(FetchMode.SUBSELECT)
     protected Set<AttachmentPE> getInternalAttachments()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/ProjectPE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/ProjectPE.java
index a872e9812a50a9c4c79746f6df494c30185dbb09..45044d566a042a6bb0cf24a7ae1c846bfc534139 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/ProjectPE.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/ProjectPE.java
@@ -22,6 +22,7 @@ import java.util.Date;
 import java.util.List;
 import java.util.Set;
 
+import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
@@ -40,6 +41,7 @@ import javax.persistence.Version;
 import org.apache.commons.lang.builder.EqualsBuilder;
 import org.apache.commons.lang.builder.HashCodeBuilder;
 import org.apache.commons.lang.builder.ToStringBuilder;
+import org.hibernate.annotations.Cascade;
 import org.hibernate.annotations.Fetch;
 import org.hibernate.annotations.FetchMode;
 import org.hibernate.annotations.Generated;
@@ -326,7 +328,8 @@ public final class ProjectPE extends AttachmentHolderPE implements Comparable<Pr
     }
 
     @Override
-    @OneToMany(fetch = FetchType.LAZY, mappedBy = "projectParentInternal")
+    @OneToMany(fetch = FetchType.LAZY, mappedBy = "projectParentInternal", cascade = CascadeType.ALL)
+    @Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
     @IndexedEmbedded(prefix = SearchFieldConstants.PREFIX_ATTACHMENT)
     @Fetch(FetchMode.SUBSELECT)
     protected Set<AttachmentPE> getInternalAttachments()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SamplePE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SamplePE.java
index 2f7d6c39d183fab617d7ae47013e161f02d372ba..9d68145fc9b6a117e8aa9b7a045c2bad0b368a47 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SamplePE.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/SamplePE.java
@@ -694,7 +694,8 @@ public class SamplePE extends AttachmentHolderPE implements IIdAndCodeHolder, Co
     }
 
     @Override
-    @OneToMany(fetch = FetchType.LAZY, mappedBy = "sampleParentInternal")
+    @OneToMany(fetch = FetchType.LAZY, mappedBy = "sampleParentInternal", cascade = CascadeType.ALL)
+    @Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
     @IndexedEmbedded(prefix = SearchFieldConstants.PREFIX_ATTACHMENT)
     @Fetch(FetchMode.SUBSELECT)
     protected Set<AttachmentPE> getInternalAttachments()
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAOTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAOTest.java
index 80574a7c42ef61e93a6c995f19ed8cd20b85e702..baa558a58e3448eb02d66721541024f78badaab3 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAOTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAOTest.java
@@ -274,26 +274,38 @@ public class ExperimentDAOTest extends AbstractDAOTest
         }
     }
 
-    @Test(expectedExceptions = DataIntegrityViolationException.class)
-    public final void testDeleteFailWithAttachments()
+    private static final String ATT_CONTENTS_TABLE = "attachment_contents";
+
+    @Test
+    public final void testDeleteWithAttachments()
     {
         final IExperimentDAO experimentDAO = daoFactory.getExperimentDAO();
         final ExperimentPE deletedExperiment = findExperiment("/CISD/DEFAULT/EXP-X");
 
         // Deleted experiment should have attachments which prevent it from deletion.
-        // Other connections which also prevent sample deletion should be empty in this test.
+        // Other connections which also prevent experiment deletion should be empty in this test.
 
         // Currently there is no such experiment in test DB so we first add an attachment
-        // to an experiment empty experiment (with no connections).
+        // to an empty experiment (with no connections).
+        int rowsInAttachmentContents = countRowsInTable(ATT_CONTENTS_TABLE);
+
         AttachmentPE attachment = CommonTestUtils.createAttachment();
+        attachment.setRegistrator(deletedExperiment.getRegistrator());
         daoFactory.getAttachmentDAO().createAttachment(attachment, deletedExperiment);
 
+        assertEquals(rowsInAttachmentContents + 1, countRowsInTable(ATT_CONTENTS_TABLE));
+
         assertFalse(deletedExperiment.getAttachments().isEmpty());
         assertTrue(deletedExperiment.getDataSets().isEmpty());
         assertTrue(deletedExperiment.getSamples().isEmpty());
 
         // delete
         experimentDAO.delete(deletedExperiment);
+
+        // test successful deletion of experiment, attachment & content
+        assertNull(experimentDAO.tryGetByTechId(TechId.create(deletedExperiment)));
+        assertNull(daoFactory.getAttachmentDAO().tryGetByTechId(TechId.create(attachment)));
+        assertEquals(rowsInAttachmentContents, countRowsInTable(ATT_CONTENTS_TABLE));
     }
 
     @Test(expectedExceptions = DataIntegrityViolationException.class)
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAOTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAOTest.java
index e54c7c20f5928e0c865894dc21547ae61f5efbb5..ceed326a2d5be1500dad39d6cbace2b8c005015d 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAOTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/SampleDAOTest.java
@@ -47,12 +47,12 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.EventPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EventPE.EntityType;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EventType;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePropertyPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SampleRelationshipPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SampleTypePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind;
 import ch.systemsx.cisd.openbis.generic.shared.util.HibernateUtils;
 
@@ -370,20 +370,37 @@ public final class SampleDAOTest extends AbstractDAOTest
         }
     }
 
-    @Test(expectedExceptions = DataIntegrityViolationException.class)
-    public final void testDeleteFailWithAttachments()
+    private static final String ATT_CONTENTS_TABLE = "attachment_contents";
+
+    @Test
+    public final void testDeleteWithAttachments()
     {
+        final ISampleDAO sampleDAO = daoFactory.getSampleDAO();
         final SamplePE deletedSample = findSample("3VCP6", "CISD");
 
-        // Deleted sample should have attachments which prevent it from deletion.
-        // Other connections which also prevent sample deletion should be empty in this test.
+        // Deleted sample should have attachments which should be deleted as well as the sample.
         assertFalse(deletedSample.getAttachments().isEmpty());
+        List<TechId> attachmentIds = TechId.createList(deletedSample.getAttachments());
+        // Other connections which would prevent sample deletion should be empty in this test.
         assertTrue(deletedSample.getDatasets().isEmpty());
         assertTrue(deletedSample.getGenerated().isEmpty());
         assertTrue(deletedSample.getContained().isEmpty());
 
+        int rowsInAttachmentContents = countRowsInTable(ATT_CONTENTS_TABLE);
+
         // delete
         deleteSample(deletedSample);
+
+        // test successful deletion of sample
+        assertNull(sampleDAO.tryGetByTechId(TechId.create(deletedSample)));
+
+        // test successful deletion of attachments & their contents
+        for (TechId attachmentId : attachmentIds)
+        {
+            assertNull(daoFactory.getAttachmentDAO().tryGetByTechId(attachmentId));
+        }
+        assertEquals(rowsInAttachmentContents - attachmentIds.size(),
+                countRowsInTable(ATT_CONTENTS_TABLE));
     }
 
     @Test(expectedExceptions = DataIntegrityViolationException.class)