diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/CreatePropertyAssignmentsExecutor.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/CreatePropertyAssignmentsExecutor.java
index 20db102bb7c4e970466d0eb09cb1e6045540ee9e..cbda655a184b917d56bc718a2e9238b2588cb93a 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/CreatePropertyAssignmentsExecutor.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/CreatePropertyAssignmentsExecutor.java
@@ -26,6 +26,7 @@ import java.util.regex.Pattern;
 
 import javax.annotation.Resource;
 
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataTypeCode;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
@@ -54,6 +55,12 @@ import ch.systemsx.cisd.openbis.generic.shared.translator.DtoConverters;
 @Component
 public class CreatePropertyAssignmentsExecutor
 {
+    private static final List<DataTypeCode> NOT_ALLOWED_PATTERN_VALIDATION_DATA_TYPES =
+            List.of(DataTypeCode.ARRAY_INTEGER, DataTypeCode.ARRAY_REAL, DataTypeCode.ARRAY_STRING,
+                    DataTypeCode.ARRAY_TIMESTAMP, DataTypeCode.SAMPLE, DataTypeCode.MATERIAL,
+                    DataTypeCode.BOOLEAN, DataTypeCode.CONTROLLEDVOCABULARY, DataTypeCode.JSON,
+                    DataTypeCode.XML);
+
     @Resource(name = ComponentNames.COMMON_BUSINESS_OBJECT_FACTORY)
     protected ICommonBusinessObjectFactory businessObjectFactory;
 
@@ -65,7 +72,7 @@ public class CreatePropertyAssignmentsExecutor
 
     @Autowired
     private IPatternCompiler patternCompiler;
-    
+
     public void createPropertyAssignments(final IOperationContext context, String entityTypeCode,
             Collection<? extends PropertyAssignmentCreation> propertyAssignments, ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind entityKind)
     {
@@ -154,6 +161,14 @@ public class CreatePropertyAssignmentsExecutor
         {
             throw new UserFailureException("Pattern and Pattern Type must be both either empty or non-empty!");
         }
+        if(assignmentCreation.getPatternType() != null && !assignmentCreation.getPatternType().trim().isEmpty())
+        {
+            DataTypeCode code = propertyTypePE.getType().getCode();
+            if(NOT_ALLOWED_PATTERN_VALIDATION_DATA_TYPES.contains(code)) {
+                throw new UserFailureException("Pattern validation can not be assigned for property of data type: " + code);
+            }
+        }
+
         assignment.setPatternType(assignmentCreation.getPatternType());
         assignment.setPattern(assignmentCreation.getPattern());
         Pattern pattern = patternCompiler.compilePattern(assignmentCreation.getPattern(), assignmentCreation.getPatternType());
diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/property/CreatePropertyTypeExecutor.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/property/CreatePropertyTypeExecutor.java
index d21545ec4e39b16729486582c610d4b120e2991c..c91655d9d2ba9b4457f8af876dae265edc146874 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/property/CreatePropertyTypeExecutor.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/property/CreatePropertyTypeExecutor.java
@@ -20,10 +20,8 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.function.Function;
-import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
-import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.IPatternCompiler;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.dao.DataAccessException;
@@ -76,8 +74,6 @@ public class CreatePropertyTypeExecutor
     @Autowired
     private IPropertyTypeAuthorizationExecutor authorizationExecutor;
 
-    @Autowired
-    private IPatternCompiler patternCompiler;
 
     @Override
     protected IObjectId getId(PropertyTypePE entity)
diff --git a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/AbstractCommonEntityTest.java b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/AbstractCommonEntityTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..c65c1a2591a102a79888db978c7e4f78efadfb02
--- /dev/null
+++ b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/AbstractCommonEntityTest.java
@@ -0,0 +1,435 @@
+package ch.ethz.sis.openbis.systemtest.asapi.v3;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.entity.AbstractEntity;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.entity.AbstractEntityCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.entity.AbstractEntityUpdate;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.id.IObjectId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IEntityType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.create.IEntityTypeCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.update.IEntityTypeUpdate;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.DataType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.PropertyAssignment;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.create.PropertyAssignmentCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.create.PropertyTypeCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.id.PropertyTypePermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.create.VocabularyCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.create.VocabularyTermCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.id.VocabularyPermId;
+import ch.systemsx.cisd.common.action.IDelegatedAction;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Abstract test class for creation of tests that share common logic among Sample, Experiment and DataSet entities
+ * @param <TYPE_CREATION>
+ * @param <TYPE>
+ * @param <ENTITY_CREATION>
+ * @param <ENTITY>
+ */
+public abstract class AbstractCommonEntityTest<TYPE_CREATION extends IEntityTypeCreation, TYPE extends IEntityType, TYPE_UPDATE extends IEntityTypeUpdate,
+        ENTITY_CREATION extends AbstractEntityCreation, ENTITY extends AbstractEntity<ENTITY>, ENTITY_UPDATE extends AbstractEntityUpdate, ENTITY_ID extends IObjectId> extends AbstractTest
+{
+    private static final String PATTERN_VALIDATION_PROVIDER = "providePatterns";
+    private static final String DATA_TYPE_PATTERN_VALIDATION_PROVIDER = "providePatternsAndDataTypes";
+    private static final String DATA_TYPE_PATTERN_VALIDATION_UPDATE_PROVIDER = "providePatternsAndDataTypesForUpdate";
+    private static final String UPDATE_ENTITY_AND_PATTERN_PROVIDER = "providePatternAdnEntityDataForUpdate";
+
+    private static final List<DataType> DATA_TYPES_THAT_ACCEPT_PATTERN = Arrays.asList(DataType.REAL,
+            DataType.INTEGER, DataType.VARCHAR, DataType.MULTILINE_VARCHAR, DataType.TIMESTAMP, DataType.DATE, DataType.HYPERLINK);
+
+
+    protected abstract TYPE_CREATION newTypeCreation();
+
+    protected abstract ENTITY_CREATION newEntityCreation(TYPE type, String code);
+
+    protected abstract TYPE_UPDATE newTypeUpdate(String typeCode);
+
+    protected abstract ENTITY_UPDATE newEntityUpdate(String permId);
+
+    protected abstract void createType(String sessionToken, TYPE_CREATION creation);
+
+    protected abstract TYPE getType(String sessionToken, String typeCode);
+
+    protected abstract ENTITY_ID createEntity(String sessionToken, ENTITY_CREATION creation);
+
+    protected abstract ENTITY getEntity(String sessionToken, ENTITY_ID id);
+
+    protected abstract void updateType(String sessionToken, TYPE_UPDATE update);
+
+    protected abstract void updateEntity(String sessionToken, ENTITY_UPDATE update);
+
+    @Test(dataProvider = PATTERN_VALIDATION_PROVIDER)
+    public void testCreateWithPatternValidation(DataType dataType, String patternType, String pattern, String input, boolean shouldFail) {
+        final String sessionToken = v3api.login(TEST_USER, PASSWORD);
+
+        final String propertyCode = "MY_TEST_PROPERTY";
+        createPropertyType(sessionToken, propertyCode, dataType);
+
+        PropertyAssignmentCreation assignmentCreation = new PropertyAssignmentCreation();
+        assignmentCreation.setPropertyTypeId(new PropertyTypePermId(propertyCode));
+        assignmentCreation.setPatternType(patternType);
+        assignmentCreation.setPattern(pattern);
+
+        final TYPE_CREATION typeCreation = newTypeCreation();
+        typeCreation.setCode("NEW_ENITTY_TYPE");
+        typeCreation.setDescription("test description");
+        typeCreation.setPropertyAssignments(Arrays.asList(assignmentCreation));
+
+        createType(sessionToken, typeCreation);
+        TYPE type = getType(sessionToken, typeCreation.getCode());
+
+        final ENTITY_CREATION creation = newEntityCreation(type, "NEW_ENTITY_1");
+        creation.setProperty(propertyCode, input);
+
+        if(shouldFail) {
+            assertUserFailureException(new IDelegatedAction()
+            {
+                @Override
+                public void execute()
+                {
+                    createEntity(sessionToken, creation);
+                }
+            }, dataType == DataType.TIMESTAMP ? " is not matching defined pattern!" :
+                                "Value: '"+input+"' is not matching defined pattern!");
+        } else {
+            ENTITY_ID entityId = createEntity(sessionToken, creation);
+            ENTITY entity = getEntity(sessionToken, entityId);
+            if(dataType == DataType.TIMESTAMP)
+            {
+                assertTrue(entity.getProperty(propertyCode).toString().startsWith(input));
+            } else {
+                assertEquals(entity.getProperty(propertyCode), input);
+            }
+        }
+    }
+
+    @DataProvider(name = PATTERN_VALIDATION_PROVIDER)
+    protected Object[][] providePatterns()
+    {
+        List<Object[]> result = new ArrayList<>();
+        for(DataType dataType : DATA_TYPES_THAT_ACCEPT_PATTERN)
+        {
+            if(dataType == DataType.DATE)
+            {
+                result.add(new Object[] { dataType, "PATTERN", "2022.*", "2022-04-08", false});
+                result.add(new Object[] { dataType, "PATTERN", "2022.*", "2024-05-16", true});
+                result.add(new Object[] { dataType, "VALUES", "\"2022-04-08\"", "2022-04-08", false});
+                result.add(new Object[] { dataType, "VALUES", "\"2022-04-08\"", "2024-04-08", true});
+            } else if(dataType == DataType.TIMESTAMP)
+            {
+                result.add(new Object[] { dataType, "PATTERN", "2022.*", "2022-05-16 04:24:00", false});
+                result.add(new Object[] { dataType, "PATTERN", "2022.*", "2024-05-16 04:22:00", true});
+            } else if(dataType == DataType.REAL) {
+                result.add(new Object[] { dataType, "PATTERN", "[1-3]{3}\\.0", "123.0", false});
+                result.add(new Object[] { dataType, "PATTERN", "[1-3]{3}\\.0", "124.0", true});
+                result.add(new Object[] { dataType, "RANGES", "1-10", "5.1", false});
+                result.add(new Object[] { dataType, "RANGES", "1-10", "11.0", true});
+                result.add(new Object[] { dataType, "VALUES", "\"2.0\"", "2.0", false});
+                result.add(new Object[] { dataType, "VALUES", "\"2.0\"", "2.1", true});
+            } else if(dataType == DataType.INTEGER) {
+                result.add(new Object[] { dataType, "PATTERN", "[1-3]{3}", "123", false});
+                result.add(new Object[] { dataType, "PATTERN", "[1-3]{3}", "124", true});
+                result.add(new Object[] { dataType, "RANGES", "1-10", "5", false});
+                result.add(new Object[] { dataType, "RANGES", "1-10", "11", true});
+                result.add(new Object[] { dataType, "VALUES", "\"2\"", "2", false});
+                result.add(new Object[] { dataType, "VALUES", "\"2\"", "3", true});
+            } else if(dataType == DataType.HYPERLINK) {
+                result.add(new Object[] { dataType, "PATTERN", "http://.*", "http://b.com", false});
+                result.add(new Object[] { dataType, "PATTERN", "http://.*", "https://a.com", true});
+                result.add(new Object[] { dataType, "VALUES", "\"http://b.com\"", "http://b.com", false});
+                result.add(new Object[] { dataType, "VALUES", "\"http://b.com\"", "http://bc.com", true});
+            }else {
+                result.add(new Object[] { dataType, "PATTERN", ".*", "abc", false});
+                result.add(new Object[] { dataType, "PATTERN", "[a-z]{3}\\d", "abc1", false});
+                result.add(new Object[] { dataType, "PATTERN", "[a-z]{3}\\d", "Abc1", true});
+                result.add(new Object[] { dataType, "PATTERN", "[a-z]{3}\\d", "abc31", true});
+                result.add(new Object[] { dataType, "RANGES", "1-5, 10-100, (-3)-(-5)", "-4", false});
+                result.add(new Object[] { dataType, "RANGES", "1-5, 10-100, (-5)-(-3)", "11", false});
+                result.add(new Object[] { dataType, "RANGES", "1-5, 10-100, (-5)-(-3)", "6", true});
+                result.add(new Object[] { dataType, "RANGES", "1-5, 10-100, (-5)-(-3)", "4.5000", false});
+                result.add(new Object[] { dataType, "VALUES", "\"a\", \"b\", \"c\"", "a", false});
+                result.add(new Object[] { dataType, "VALUES", "\"a\", \"b\", \"c\"", "d", true});
+            }
+        }
+        return result.toArray(new Object[result.size()][6]);
+    }
+
+    @Test(dataProvider = DATA_TYPE_PATTERN_VALIDATION_PROVIDER)
+    public void testAssignPatternsToPropertyTypes(DataType dataType, boolean isCorrect, String patternType, String pattern) {
+        final String sessionToken = v3api.login(TEST_USER, PASSWORD);
+
+        final String propertyCode = "MY_TEST_PROPERTY";
+        createPropertyType(sessionToken, propertyCode, dataType);
+
+        PropertyAssignmentCreation assignmentCreation = new PropertyAssignmentCreation();
+        assignmentCreation.setPropertyTypeId(new PropertyTypePermId(propertyCode));
+        assignmentCreation.setPatternType(patternType);
+        assignmentCreation.setPattern(pattern);
+
+        final TYPE_CREATION typeCreation = newTypeCreation();
+        typeCreation.setCode("NEW_ENITTY_TYPE");
+        typeCreation.setDescription("test description");
+        typeCreation.setPropertyAssignments(Arrays.asList(assignmentCreation));
+
+        if(isCorrect) {
+            createType(sessionToken, typeCreation);
+            TYPE type = getType(sessionToken, typeCreation.getCode());
+            assertEquals(type.getPropertyAssignments().size(), 1);
+
+            PropertyAssignment assignment = type.getPropertyAssignments().get(0);
+            assertEquals(assignment.getPatternType(), patternType);
+            assertEquals(assignment.getPattern(), pattern);
+        } else {
+            assertUserFailureException(new IDelegatedAction()
+            {
+                @Override
+                public void execute()
+                {
+                    createType(sessionToken, typeCreation);
+                }
+            }, "Pattern validation can not be assigned for property of data type: " + dataType);
+        }
+
+    }
+
+    @DataProvider(name = DATA_TYPE_PATTERN_VALIDATION_PROVIDER)
+    protected Object[][] providePatternsAndDataTypes()
+    {
+        List<Object[]> result = new ArrayList<>();
+        for(Object dataType : DataType.values())
+        {
+            for(Object[] patterns : properPatterns())
+            {
+                List<Object> test = new ArrayList<>();
+                test.add(dataType);
+                test.add(DATA_TYPES_THAT_ACCEPT_PATTERN.contains(dataType));
+                test.addAll(Arrays.asList(patterns));
+                result.add(test.toArray(new Object[4]));
+            }
+        }
+        return result.toArray(new Object[result.size()][4]);
+    }
+
+
+    private Object[][] properPatterns()
+    {
+        return new Object[][] { {"PATTERN", ".*"}, {"PATTERN", "[a-c]{3}\\d"}, {"PATTERN", "\\d{3}"},
+                { "RANGES", "1-10"}, {"RANGES", "(-1)-5"}, {"RANGES", "100-10"},
+                { "VALUES", "\"a\", \"b\", \"c\""}, { "VALUES", "\"Foo\", \"Bar\""},
+                { "VALUES", "\"Piotr\", \"Juan\", \"Viktor\", \"Adam\", \"Mihai\""}
+        };
+    }
+
+    @Test(dataProvider = DATA_TYPE_PATTERN_VALIDATION_UPDATE_PROVIDER)
+    public void testCreateAndUpdatePattern(DataType dataType, String patternType, String pattern, String patternTypeUpdate, String patternUpdate)
+    {
+        final String sessionToken = v3api.login(TEST_USER, PASSWORD);
+
+        // PROPERTY CREATION
+        final String propertyCode = "MY_TEST_PROPERTY";
+        createPropertyType(sessionToken, propertyCode, dataType);
+
+        // TYPE CREATION
+        PropertyAssignmentCreation assignmentCreation = new PropertyAssignmentCreation();
+        assignmentCreation.setPropertyTypeId(new PropertyTypePermId(propertyCode));
+        assignmentCreation.setPatternType(patternType);
+        assignmentCreation.setPattern(pattern);
+
+        final TYPE_CREATION typeCreation = newTypeCreation();
+        typeCreation.setCode("NEW_ENITTY_TYPE");
+        typeCreation.setDescription("test description");
+        typeCreation.setPropertyAssignments(Arrays.asList(assignmentCreation));
+
+        createType(sessionToken, typeCreation);
+        TYPE type = getType(sessionToken, typeCreation.getCode());
+        assertEquals(type.getPropertyAssignments().size(), 1);
+
+        PropertyAssignment assignment = type.getPropertyAssignments().get(0);
+        assertEquals(assignment.getPatternType(), patternType);
+        assertEquals(assignment.getPattern(), pattern);
+
+        // TYPE UPDATE
+        PropertyAssignmentCreation propertyAssignmentForUpdate = new PropertyAssignmentCreation();
+        propertyAssignmentForUpdate.setPropertyTypeId(new PropertyTypePermId(propertyCode));
+        propertyAssignmentForUpdate.setPatternType(patternTypeUpdate);
+        propertyAssignmentForUpdate.setPattern(patternUpdate);
+
+        final TYPE_UPDATE typeUpdate = newTypeUpdate(typeCreation.getCode());
+        typeUpdate.getPropertyAssignments().set(propertyAssignmentForUpdate);
+
+        updateType(sessionToken, typeUpdate);
+        TYPE typeUpdated = getType(sessionToken, typeCreation.getCode());
+        assertEquals(typeUpdated.getPropertyAssignments().size(), 1);
+
+        PropertyAssignment assignmentUpdated = typeUpdated.getPropertyAssignments().get(0);
+        assertEquals(assignmentUpdated.getPatternType(), patternTypeUpdate);
+        assertEquals(assignmentUpdated.getPattern(), patternUpdate);
+    }
+
+    @DataProvider(name = DATA_TYPE_PATTERN_VALIDATION_UPDATE_PROVIDER)
+    protected Object[][] providePatternsAndDataTypesForUpdate()
+    {
+        List<Object[]> result = new ArrayList<>();
+        for(Object dataType : DATA_TYPES_THAT_ACCEPT_PATTERN)
+        {
+            Object[][] patterns = properPatterns();
+            int size = patterns.length;
+            for(int i=0; i<size; i++)
+            {
+                List<Object> test = new ArrayList<>();
+                test.add(dataType);
+                test.addAll(Arrays.asList(patterns[i]));
+                test.addAll(Arrays.asList(patterns[(i+1)%size]));
+                result.add(test.toArray(new Object[5]));
+            }
+        }
+        return result.toArray(new Object[result.size()][5]);
+    }
+
+    @Test(dataProvider = UPDATE_ENTITY_AND_PATTERN_PROVIDER)
+    public void testCreateAndUpdateEntityPatternProperty(DataType dataType, String baseInput, String updatePatternType, String updatePattern, String updateValue, boolean shouldFail)
+    {
+        final String sessionToken = v3api.login(TEST_USER, PASSWORD);
+
+        final String propertyCode = "MY_TEST_PROPERTY";
+        createPropertyType(sessionToken, propertyCode, dataType);
+
+        PropertyAssignmentCreation assignmentCreation = new PropertyAssignmentCreation();
+        assignmentCreation.setPropertyTypeId(new PropertyTypePermId(propertyCode));
+        assignmentCreation.setPatternType("PATTERN");
+        assignmentCreation.setPattern(".*");
+
+        final TYPE_CREATION typeCreation = newTypeCreation();
+        typeCreation.setCode("NEW_ENITTY_TYPE");
+        typeCreation.setDescription("test description");
+        typeCreation.setPropertyAssignments(Arrays.asList(assignmentCreation));
+
+        createType(sessionToken, typeCreation);
+        TYPE type = getType(sessionToken, typeCreation.getCode());
+
+        final ENTITY_CREATION creation = newEntityCreation(type, "NEW_ENTITY_1");
+        creation.setProperty(propertyCode, baseInput);
+        ENTITY_ID entityId = createEntity(sessionToken, creation);
+        ENTITY entity = getEntity(sessionToken, entityId);
+        if(dataType == DataType.TIMESTAMP) {
+            assertTrue(entity.getProperty(propertyCode).toString().startsWith(baseInput));
+        } else {
+            assertEquals(entity.getProperty(propertyCode), baseInput);
+        }
+
+        // TYPE UPDATE
+        PropertyAssignmentCreation propertyAssignmentForUpdate = new PropertyAssignmentCreation();
+        propertyAssignmentForUpdate.setPropertyTypeId(new PropertyTypePermId(propertyCode));
+        propertyAssignmentForUpdate.setPatternType(updatePatternType);
+        propertyAssignmentForUpdate.setPattern(updatePattern);
+
+        final TYPE_UPDATE typeUpdate = newTypeUpdate(typeCreation.getCode());
+        typeUpdate.getPropertyAssignments().set(propertyAssignmentForUpdate);
+
+        updateType(sessionToken, typeUpdate);
+        TYPE typeUpdated = getType(sessionToken, typeCreation.getCode());
+        assertEquals(typeUpdated.getPropertyAssignments().size(), 1);
+
+        PropertyAssignment assignmentUpdated = typeUpdated.getPropertyAssignments().get(0);
+        assertEquals(assignmentUpdated.getPatternType(), updatePatternType);
+        assertEquals(assignmentUpdated.getPattern(), updatePattern);
+
+        // ENTITY UPDATE
+        final ENTITY_UPDATE entityUpdate = newEntityUpdate(entityId.toString());
+        entityUpdate.setProperty(propertyCode, updateValue);
+
+        if(shouldFail) {
+            assertUserFailureException(new IDelegatedAction()
+            {
+                @Override
+                public void execute()
+                {
+                    updateEntity(sessionToken, entityUpdate);
+                }
+            }, dataType == DataType.TIMESTAMP ? "is not matching defined pattern!"
+                    : "Value: '"+updateValue+"' is not matching defined pattern!");
+
+        } else {
+            updateEntity(sessionToken, entityUpdate);
+            ENTITY entityUpdated = getEntity(sessionToken, entityId);
+            if(dataType == DataType.TIMESTAMP) {
+                assertTrue(entityUpdated.getProperty(propertyCode).toString().startsWith(updateValue));
+            } else {
+                assertEquals(entityUpdated.getProperty(propertyCode), updateValue);
+            }
+
+        }
+    }
+
+    @DataProvider(name = UPDATE_ENTITY_AND_PATTERN_PROVIDER)
+    protected Object[][] getDataForUpdate()
+    {
+        List<Object[]> result = new ArrayList<>();
+        for(DataType dataType : DATA_TYPES_THAT_ACCEPT_PATTERN)
+        {
+            if(dataType == DataType.DATE)
+            {
+                result.add(new Object[] { dataType, "2022-05-16", "PATTERN", "2022.*", "2022-04-08", false});
+                result.add(new Object[] { dataType, "2022-05-16", "PATTERN", "2022.*", "2024-05-16", true});
+                result.add(new Object[] { dataType, "2022-05-16", "VALUES", "\"2022-04-08\"", "2022-04-08", false});
+                result.add(new Object[] { dataType, "2022-05-16", "VALUES", "\"2022-04-08\"", "2024-04-08", true});
+            } else if(dataType == DataType.TIMESTAMP)
+            {
+                result.add(new Object[] { dataType, "2022-05-16 04:22", "PATTERN", "2022.*", "2022-05-16 04:24:00", false});
+                result.add(new Object[] { dataType, "2022-05-16 04:22", "PATTERN", "2022.*", "2024-05-16 04:22:00", true});
+            } else if(dataType == DataType.REAL) {
+                result.add(new Object[] { dataType, "1.0", "PATTERN", "[1-3]{3}\\.0", "123.0", false});
+                result.add(new Object[] { dataType, "1.0", "PATTERN", "[1-3]{3}\\.0", "124.0", true});
+                result.add(new Object[] { dataType, "1.0", "RANGES", "1-10", "5.1", false});
+                result.add(new Object[] { dataType, "1.0", "RANGES", "1-10", "11.0", true});
+                result.add(new Object[] { dataType, "1.0", "VALUES", "\"2.0\"", "2.0", false});
+                result.add(new Object[] { dataType, "1.0", "VALUES", "\"2.0\"", "2.1", true});
+            } else if(dataType == DataType.HYPERLINK) {
+                result.add(new Object[] { dataType, "http://a.com", "PATTERN", "http://.*", "http://b.com", false});
+                result.add(new Object[] { dataType, "http://a.com", "PATTERN", "http://.*", "https://a.com", true});
+                result.add(new Object[] { dataType, "http://a.com", "VALUES", "\"http://b.com\"", "http://b.com", false});
+                result.add(new Object[] { dataType, "http://a.com", "VALUES", "\"http://b.com\"", "http://bc.com", true});
+            }else {
+                result.add(new Object[] { dataType, "1", "PATTERN", "[1-3]{3}", "123", false});
+                result.add(new Object[] { dataType, "1", "PATTERN", "[1-3]{3}", "124", true});
+                result.add(new Object[] { dataType, "1", "RANGES", "1-10", "5", false});
+                result.add(new Object[] { dataType, "1", "RANGES", "1-10", "11", true});
+                result.add(new Object[] { dataType, "1", "VALUES", "\"1\"", "1", false});
+                result.add(new Object[] { dataType, "1", "VALUES", "\"1\"", "2", true});
+            }
+        }
+        return result.toArray(new Object[result.size()][6]);
+    }
+
+    protected void createPropertyType(String sessionToken, String propertyCode, DataType dataType)
+    {
+        PropertyTypeCreation propertyTypeCreation = new PropertyTypeCreation();
+        propertyTypeCreation.setCode(propertyCode);
+        propertyTypeCreation.setDataType(dataType);
+        if(dataType == DataType.CONTROLLEDVOCABULARY) {
+            VocabularyCreation vocabularyCreation = new VocabularyCreation();
+            vocabularyCreation.setCode("TEST_VOCABULARY_PATTERN");
+
+            VocabularyTermCreation vtCreation = new VocabularyTermCreation();
+            vtCreation.setCode("TERM1");
+            vtCreation.setLabel("term1");
+
+            vocabularyCreation.setTerms(Arrays.asList(vtCreation));
+
+            List<VocabularyPermId> ids = v3api.createVocabularies(sessionToken, Arrays.asList(vocabularyCreation));
+            propertyTypeCreation.setVocabularyId(ids.get(0));
+        }
+        propertyTypeCreation.setLabel("label");
+        propertyTypeCreation.setDescription("description");
+
+        v3api.createPropertyTypes(sessionToken, Arrays.asList(propertyTypeCreation));
+    }
+
+}
diff --git a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/AbstractTest.java b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/AbstractTest.java
index 43159dcdc8bd0a046b3e84544aa97f4153387bec..8ce4d870776aeff1f8a7c576e39f8f374ad605e7 100644
--- a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/AbstractTest.java
+++ b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/AbstractTest.java
@@ -1856,7 +1856,7 @@ public class AbstractTest extends SystemTestCase
         return map.get(tokenId);
     }
 
-    @DataProvider
+    @DataProvider (name = USER_ROLES_PROVIDER)
     protected Object[][] provideUserRoles()
     {
         return createProvider(RoleWithHierarchy.INSTANCE_ADMIN, RoleWithHierarchy.INSTANCE_OBSERVER, RoleWithHierarchy.SPACE_ADMIN,
diff --git a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/DataSetCommonEntityTest.java b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/DataSetCommonEntityTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ab3b042c00725412ddc6fbb29d531b65f3eb2769
--- /dev/null
+++ b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/DataSetCommonEntityTest.java
@@ -0,0 +1,121 @@
+package ch.ethz.sis.openbis.systemtest.asapi.v3;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.id.CreationId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSet;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetKind;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.DataSetCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.DataSetTypeCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.PhysicalDataCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.fetchoptions.DataSetFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.fetchoptions.DataSetTypeFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.*;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.update.DataSetTypeUpdate;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.update.DataSetUpdate;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.datastore.id.DataStorePermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id.EntityTypePermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentIdentifier;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class DataSetCommonEntityTest extends AbstractCommonEntityTest<DataSetTypeCreation, DataSetType, DataSetTypeUpdate, DataSetCreation, DataSet, DataSetUpdate, IDataSetId>
+{
+    @Override
+    protected DataSetTypeCreation newTypeCreation()
+    {
+        return new DataSetTypeCreation();
+    }
+
+    @Override
+    protected DataSetCreation newEntityCreation(DataSetType type, String code)
+    {
+        PhysicalDataCreation physicalCreation = new PhysicalDataCreation();
+        physicalCreation.setLocation("test/location/" + code);
+        physicalCreation.setFileFormatTypeId(new FileFormatTypePermId("TIFF"));
+        physicalCreation.setLocatorTypeId(new RelativeLocationLocatorTypePermId());
+        physicalCreation.setStorageFormatId(new ProprietaryStorageFormatPermId());
+
+        DataSetCreation creation = new DataSetCreation();
+        creation.setCode(code);
+        creation.setDataSetKind(DataSetKind.PHYSICAL);
+        creation.setTypeId(type.getPermId());
+        creation.setExperimentId(new ExperimentIdentifier("/CISD/NEMO/EXP1"));
+        creation.setDataStoreId(new DataStorePermId("STANDARD"));
+        creation.setPhysicalData(physicalCreation);
+        creation.setCreationId(new CreationId(code));
+
+        return creation;
+    }
+
+    @Override
+    protected DataSetTypeUpdate newTypeUpdate(String typeCode)
+    {
+        DataSetTypeUpdate update = new DataSetTypeUpdate();
+        update.setTypeId(new EntityTypePermId(typeCode));
+        return update;
+    }
+
+    @Override
+    protected DataSetUpdate newEntityUpdate(String permId)
+    {
+        DataSetUpdate update = new DataSetUpdate();
+        update.setDataSetId(new DataSetPermId(permId));
+        return update;
+    }
+
+    @Override
+    protected void createType(String sessionToken, DataSetTypeCreation creations)
+    {
+        v3api.createDataSetTypes(sessionToken, Arrays.asList(creations));
+    }
+
+    @Override
+    protected DataSetType getType(String sessionToken, String typeCode)
+    {
+        final DataSetTypeFetchOptions fo = new DataSetTypeFetchOptions();
+        fo.withPropertyAssignments().withPropertyType();
+        fo.withPropertyAssignments().withRegistrator();
+
+        final EntityTypePermId permId = new EntityTypePermId(typeCode);
+        return v3api.getDataSetTypes(sessionToken, Collections.singletonList(permId), fo)
+                .get(permId);
+    }
+
+    @Override
+    protected IDataSetId createEntity(String sessionToken, DataSetCreation creation)
+    {
+        List<DataSetPermId> permIds = v3api.createDataSets(sessionToken, Arrays.asList(creation));
+        return permIds.get(0);
+
+    }
+
+    @Override
+    protected DataSet getEntity(String sessionToken, IDataSetId id)
+    {
+        DataSetFetchOptions fo = new DataSetFetchOptions();
+        fo.withProperties();
+        Map<IDataSetId, DataSet> dataSets = v3api.getDataSets(sessionToken, Arrays.asList(id), fo);
+        return dataSets.values().iterator().next();
+    }
+
+    @Override
+    protected void updateType(String sessionToken, DataSetTypeUpdate update)
+    {
+        v3api.updateDataSetTypes(sessionToken, Arrays.asList(update));
+    }
+
+    @Override
+    protected void updateEntity(String sessionToken, DataSetUpdate update)
+    {
+        v3api.updateDataSets(sessionToken, Arrays.asList(update));
+    }
+
+    @Test
+    public void testDummy() {
+        //dummy test for a simple test run
+    }
+}
diff --git a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExperimentCommonEntityTest.java b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExperimentCommonEntityTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5eca8bfe6553991046a844f00ee4d48282def665
--- /dev/null
+++ b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExperimentCommonEntityTest.java
@@ -0,0 +1,109 @@
+package ch.ethz.sis.openbis.systemtest.asapi.v3;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id.EntityTypePermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.Experiment;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.ExperimentType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.create.ExperimentCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.create.ExperimentTypeCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.fetchoptions.ExperimentFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.fetchoptions.ExperimentTypeFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentPermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.IExperimentId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.update.ExperimentTypeUpdate;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.update.ExperimentUpdate;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.id.ProjectIdentifier;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class ExperimentCommonEntityTest extends AbstractCommonEntityTest<ExperimentTypeCreation, ExperimentType, ExperimentTypeUpdate, ExperimentCreation, Experiment, ExperimentUpdate, IExperimentId>
+{
+
+    @Override
+    protected ExperimentTypeCreation newTypeCreation()
+    {
+        return new ExperimentTypeCreation();
+    }
+
+
+    @Override
+    protected ExperimentCreation newEntityCreation(ExperimentType type, String code)
+    {
+        ExperimentCreation creation = new ExperimentCreation();
+        creation.setTypeId(type.getPermId());
+        creation.setCode(code);
+        creation.setProjectId(new ProjectIdentifier("/TESTGROUP/TESTPROJ"));
+        return creation;
+    }
+
+    @Override
+    protected ExperimentTypeUpdate newTypeUpdate(String typeCode)
+    {
+        ExperimentTypeUpdate update = new ExperimentTypeUpdate();
+        update.setTypeId(new EntityTypePermId(typeCode));
+        return update;
+    }
+
+    @Override
+    protected ExperimentUpdate newEntityUpdate(String permId)
+    {
+        ExperimentUpdate update = new ExperimentUpdate();
+        update.setExperimentId(new ExperimentPermId(permId));
+        return update;
+    }
+
+    @Override
+    protected void createType(String sessionToken, ExperimentTypeCreation creations)
+    {
+        v3api.createExperimentTypes(sessionToken, Arrays.asList(creations));
+    }
+
+    @Override
+    protected ExperimentType getType(String sessionToken, String typeCode)
+    {
+        ExperimentTypeFetchOptions fo = new ExperimentTypeFetchOptions();
+        fo.withPropertyAssignments().withPropertyType();
+        fo.withPropertyAssignments().withRegistrator();
+
+        final EntityTypePermId permId = new EntityTypePermId(typeCode);
+        return v3api.getExperimentTypes(sessionToken, Collections.singletonList(permId), fo)
+                .get(permId);
+    }
+
+    @Override
+    protected IExperimentId createEntity(String sessionToken, ExperimentCreation creation)
+    {
+        List<ExperimentPermId> permIds = v3api.createExperiments(sessionToken, Arrays.asList(creation));
+        return permIds.get(0);
+    }
+
+    @Override
+    protected Experiment getEntity(String sessionToken, IExperimentId id)
+    {
+        ExperimentFetchOptions fo = new ExperimentFetchOptions();
+        fo.withProperties();
+        Map<IExperimentId, Experiment> experiments = v3api.getExperiments(sessionToken, Arrays.asList(id), fo);
+        return experiments.values().iterator().next();
+    }
+
+    @Override
+    protected void updateType(String sessionToken, ExperimentTypeUpdate update)
+    {
+        v3api.updateExperimentTypes(sessionToken, Arrays.asList(update));
+    }
+
+    @Override
+    protected void updateEntity(String sessionToken, ExperimentUpdate update)
+    {
+        v3api.updateExperiments(sessionToken, Arrays.asList(update));
+    }
+
+    @Test
+    public void testDummy() {
+        //dummy test for a simple test run
+    }
+}
+
diff --git a/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/SampleCommonEntityTest.java b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/SampleCommonEntityTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..33905f836fd79ad936078a496b529b542828ab73
--- /dev/null
+++ b/server-application-server/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/SampleCommonEntityTest.java
@@ -0,0 +1,106 @@
+package ch.ethz.sis.openbis.systemtest.asapi.v3;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.id.EntityTypePermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.Sample;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.SampleType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.create.SampleCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.create.SampleTypeCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.fetchoptions.SampleFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.fetchoptions.SampleTypeFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SamplePermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.update.SampleTypeUpdate;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.update.SampleUpdate;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+public class SampleCommonEntityTest extends AbstractCommonEntityTest<SampleTypeCreation, SampleType, SampleTypeUpdate, SampleCreation, Sample, SampleUpdate, ISampleId>
+{
+
+    @Override
+    protected SampleTypeCreation newTypeCreation()
+    {
+        return new SampleTypeCreation();
+    }
+
+
+    @Override
+    protected SampleCreation newEntityCreation(SampleType type, String code)
+    {
+        final SampleCreation creation = new SampleCreation();
+        creation.setTypeId(type.getPermId());
+        creation.setCode(code);
+        return creation;
+    }
+
+    @Override
+    protected SampleTypeUpdate newTypeUpdate(String typeCode)
+    {
+        SampleTypeUpdate update = new SampleTypeUpdate();
+        update.setTypeId(new EntityTypePermId(typeCode));
+        return update;
+    }
+
+    @Override
+    protected SampleUpdate newEntityUpdate(String permId)
+    {
+        SampleUpdate update = new SampleUpdate();
+        update.setSampleId(new SamplePermId(permId));
+        return update;
+    }
+
+    @Override
+    protected void createType(String sessionToken, SampleTypeCreation creations)
+    {
+        v3api.createSampleTypes(sessionToken, Arrays.asList(creations));
+    }
+
+    @Override
+    protected SampleType getType(String sessionToken, String typeCode)
+    {
+        SampleTypeFetchOptions fo = new SampleTypeFetchOptions();
+        fo.withPropertyAssignments().withPropertyType();
+        fo.withPropertyAssignments().withRegistrator();
+
+        final EntityTypePermId permId = new EntityTypePermId(typeCode);
+        return v3api.getSampleTypes(sessionToken, Collections.singletonList(permId), fo)
+                .get(permId);
+    }
+
+    @Override
+    protected ISampleId createEntity(String sessionToken, SampleCreation creation)
+    {
+        List<SamplePermId> permIds = v3api.createSamples(sessionToken, Arrays.asList(creation));
+        return permIds.get(0);
+    }
+
+    @Override
+    protected Sample getEntity(String sessionToken, ISampleId id)
+    {
+        SampleFetchOptions fo = new SampleFetchOptions();
+        fo.withProperties();
+        Map<ISampleId, Sample> samples = v3api.getSamples(sessionToken, Arrays.asList(id), fo);
+        return samples.values().iterator().next();
+    }
+
+    @Override
+    protected void updateType(String sessionToken, SampleTypeUpdate update)
+    {
+        v3api.updateSampleTypes(sessionToken, Arrays.asList(update));
+    }
+
+    @Override
+    protected void updateEntity(String sessionToken, SampleUpdate update)
+    {
+        v3api.updateSamples(sessionToken, Arrays.asList(update));
+    }
+
+    @Test
+    public void testDummy() {
+        //dummy test for a simple test run
+    }
+}