diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/VocabularyBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/VocabularyBO.java
index 7724472dd24744e49ea8cba82dbe281516b2aff0..4ff1cb108cee037bb13c32e1d3c8c20456856219 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/VocabularyBO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/VocabularyBO.java
@@ -107,6 +107,10 @@ public class VocabularyBO extends AbstractBusinessObject implements IVocabularyB
         {
             remainingTerms.remove(termToBeReplaced.getTerm().getCode());
         }
+        if (remainingTerms.isEmpty())
+        {
+            throw new IllegalArgumentException("Deletion of all " + terms.size() + " terms are not allowed.");
+        }
         for (VocabularyTermReplacement termToBeReplaced : termsToBeReplaced)
         {
             String code = termToBeReplaced.getTerm().getCode();
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/CommonServerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/CommonServerTest.java
index d7fe68f1387772d506f99d49a70e8c56d761ea64..b7596b17374549099f68053512cdb25f7b0cf1b9 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/CommonServerTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/CommonServerTest.java
@@ -39,6 +39,8 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Vocabulary;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTerm;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTermReplacement;
 import ch.systemsx.cisd.openbis.generic.shared.dto.AttachmentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EntityTypePE;
@@ -670,6 +672,31 @@ public final class CommonServerTest extends AbstractServerTestCase
         
         context.assertIsSatisfied();
     }
+    
+    @Test
+    public void testDeleteVocabularyTerms()
+    {
+        final List<VocabularyTerm> termToBeDeleted = Arrays.asList(new VocabularyTerm());
+        final List<VocabularyTermReplacement> termsToBeReplaced =
+                Arrays.asList(new VocabularyTermReplacement());
+        prepareGetSession();
+        context.checking(new Expectations()
+            {
+                {
+                    one(commonBusinessObjectFactory).createVocabularyBO(SESSION);
+                    will(returnValue(vocabularyBO));
+
+                    one(vocabularyBO).load("v-code");
+                    one(vocabularyBO).delete(termToBeDeleted, termsToBeReplaced);
+                    one(vocabularyBO).save();
+                }
+            });
+
+        createServer().deleteVocabularyTerms(SESSION_TOKEN, "v-code", termToBeDeleted,
+                termsToBeReplaced);
+
+        context.assertIsSatisfied();
+    }
 
     @Test
     public final void testAssignPropertyType()
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/VocabularyBOTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/VocabularyBOTest.java
index b810ee48c059b40a766def639b499178eb86a0f8..a5a94abdf86c00fd29a324c6d33396d6e862f0ce 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/VocabularyBOTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/VocabularyBOTest.java
@@ -20,6 +20,7 @@ import static ch.systemsx.cisd.openbis.generic.server.business.ManagerTestTool.E
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -31,8 +32,12 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.server.business.ManagerTestTool;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Vocabulary;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTerm;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTermReplacement;
+import ch.systemsx.cisd.openbis.generic.shared.dto.EntityPropertyPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MaterialPropertyPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.VocabularyPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.VocabularyTermPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind;
 
 /**
  * Test cases for corresponding {@link VocabularyBO} class.
@@ -225,4 +230,185 @@ public final class VocabularyBOTest extends AbstractBOTest
         assertSame(EXAMPLE_SESSION.tryGetPerson(), term.getRegistrator());
         context.assertIsSatisfied();
     }
+    
+    @Test
+    public void testDeleteAllTerms()
+    {
+        final VocabularyPE vocabulary = new VocabularyPE();
+        VocabularyTerm term1 = createTerm("1");
+        vocabulary.addTerm(translate(term1));
+        context.checking(new Expectations()
+            {
+                {
+                    one(vocabularyDAO).tryFindVocabularyByCode("voc-code");
+                    will(returnValue(vocabulary));
+                }
+            });
+        
+        VocabularyBO vocabularyBO = createVocabularyBO();
+        vocabularyBO.load("voc-code");
+        try
+        {
+            vocabularyBO.delete(Arrays.asList(term1), Collections.<VocabularyTermReplacement>emptyList());
+        } catch (IllegalArgumentException e)
+        {
+            assertEquals("Deletion of all 1 terms are not allowed.", e.getMessage());
+        }
+        
+        assertEquals(1, vocabulary.getTerms().size());
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testDeleteTermsWithDeletedReplacement()
+    {
+        final VocabularyPE vocabulary = new VocabularyPE();
+        VocabularyTerm term1 = createTerm("1");
+        VocabularyTerm term2 = createTerm("2");
+        VocabularyTerm term3 = createTerm("3");
+        vocabulary.addTerm(translate(term1));
+        vocabulary.addTerm(translate(term2));
+        vocabulary.addTerm(translate(term3));
+        context.checking(new Expectations()
+            {
+                {
+                    one(vocabularyDAO).tryFindVocabularyByCode("voc-code");
+                    will(returnValue(vocabulary));
+                }
+            });
+
+        VocabularyBO vocabularyBO = createVocabularyBO();
+        vocabularyBO.load("voc-code");
+        try
+        {
+            vocabularyBO.delete(Arrays.asList(term1), Arrays.asList(createTermWithReplacement(term2,
+                    term1)));
+            fail("IllegalArgumentException expected.");
+        } catch (IllegalArgumentException e)
+        {
+            assertEquals("Invalid vocabulary replacement because of unknown replacement: 2 -> 1", e
+                    .getMessage());
+        }
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testDeleteTermsWithUnkownReplacement()
+    {
+        final VocabularyPE vocabulary = new VocabularyPE();
+        VocabularyTerm term1 = createTerm("1");
+        VocabularyTerm term2 = createTerm("2");
+        VocabularyTerm term3 = createTerm("3");
+        vocabulary.addTerm(translate(term1));
+        vocabulary.addTerm(translate(term2));
+        context.checking(new Expectations()
+            {
+                {
+                    one(vocabularyDAO).tryFindVocabularyByCode("voc-code");
+                    will(returnValue(vocabulary));
+                }
+            });
+
+        VocabularyBO vocabularyBO = createVocabularyBO();
+        vocabularyBO.load("voc-code");
+        try
+        {
+            vocabularyBO.delete(Collections.<VocabularyTerm> emptyList(), Arrays
+                    .asList(createTermWithReplacement(term1, term3)));
+            fail("IllegalArgumentException expected.");
+        } catch (IllegalArgumentException e)
+        {
+            assertEquals("Invalid vocabulary replacement because of unknown replacement: 1 -> 3", e
+                    .getMessage());
+        }
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testDeleteTerms()
+    {
+        final VocabularyPE vocabulary = new VocabularyPE();
+        VocabularyTerm term1 = createTerm("1");
+        VocabularyTerm term2 = createTerm("2");
+        vocabulary.addTerm(translate(term1));
+        vocabulary.addTerm(translate(term2));
+        context.checking(new Expectations()
+        {
+            {
+                one(vocabularyDAO).tryFindVocabularyByCode("voc-code");
+                will(returnValue(vocabulary));
+            }
+        });
+        
+        VocabularyBO vocabularyBO = createVocabularyBO();
+        vocabularyBO.load("voc-code");
+        vocabularyBO.delete(Arrays.asList(term1), Collections.<VocabularyTermReplacement>emptyList());
+        
+        assertEquals(1, vocabulary.getTerms().size());
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testDeleteAndReplaceTerms()
+    {
+        final VocabularyPE vocabulary = new VocabularyPE();
+        VocabularyTerm term1 = createTerm("1");
+        final VocabularyTerm term2 = createTerm("2");
+        VocabularyTerm term3 = createTerm("3");
+        vocabulary.addTerm(translate(term1));
+        vocabulary.addTerm(translate(term2));
+        vocabulary.addTerm(translate(term3));
+        final MaterialPropertyPE entityPropertyPE = new MaterialPropertyPE();
+        context.checking(new Expectations()
+        {
+            {
+                one(vocabularyDAO).tryFindVocabularyByCode("voc-code");
+                will(returnValue(vocabulary));
+                
+                for (EntityKind entityKind : EntityKind.values())
+                {
+                    one(daoFactory).getEntityPropertyTypeDAO(entityKind);
+                    will(returnValue(entityPropertyTypeDAO));
+                    
+                    one(entityPropertyTypeDAO).listPropertiesByVocabularyTerm(term2.getCode());
+                    List<EntityPropertyPE> properties = Arrays.<EntityPropertyPE>asList(entityPropertyPE);
+                    will(returnValue(properties));
+                    
+                    one(entityPropertyTypeDAO).updateProperties(properties);
+                }
+            }
+        });
+        
+        VocabularyBO vocabularyBO = createVocabularyBO();
+        vocabularyBO.load("voc-code");
+        vocabularyBO.delete(Arrays.asList(term1), Arrays.asList(createTermWithReplacement(term2,
+                term3)));
+        
+        assertEquals(term3.getCode(), entityPropertyPE.getVocabularyTerm().getCode());
+        assertEquals(1, vocabulary.getTerms().size());
+        assertEquals(term3.getCode(), vocabulary.getTerms().iterator().next().getCode());
+        context.assertIsSatisfied();
+    }
+    
+    private VocabularyTerm createTerm(String code)
+    {
+        VocabularyTerm vocabularyTerm = new VocabularyTerm();
+        vocabularyTerm.setCode(code);
+        return vocabularyTerm;
+    }
+    
+    private VocabularyTermReplacement createTermWithReplacement(VocabularyTerm term, VocabularyTerm replacement)
+    {
+        VocabularyTermReplacement vocabularyTermReplacement = new VocabularyTermReplacement();
+        vocabularyTermReplacement.setTerm(term);
+        vocabularyTermReplacement.setReplacement(replacement.getCode());
+        return vocabularyTermReplacement;
+    }
+    
+    private VocabularyTermPE translate(VocabularyTerm term)
+    {
+        VocabularyTermPE vocabularyTermPE = new VocabularyTermPE();
+        vocabularyTermPE.setCode(term.getCode());
+        return vocabularyTermPE;
+    }
 }