diff --git a/openbis_ng_ui/src/js/components/types/form/TypeFormControllerChange.js b/openbis_ng_ui/src/js/components/types/form/TypeFormControllerChange.js
index 50a67b10e920f020fc126b2042b5b89ddd3ea5f6..1c1bbe8550298970bbb14602e42e3f63edf178e2 100644
--- a/openbis_ng_ui/src/js/components/types/form/TypeFormControllerChange.js
+++ b/openbis_ng_ui/src/js/components/types/form/TypeFormControllerChange.js
@@ -209,15 +209,15 @@ export default class TypeFormControllerChange extends PageControllerChange {
         },
         vocabulary: {
           ...newProperty.vocabulary,
-          enabled: !systemInternalPropertyType
+          enabled: !systemInternalPropertyType && !isGlobal
         },
         materialType: {
           ...newProperty.materialType,
-          enabled: !systemInternalPropertyType
+          enabled: !systemInternalPropertyType && !isGlobal
         },
         sampleType: {
           ...newProperty.sampleType,
-          enabled: !systemInternalPropertyType
+          enabled: !systemInternalPropertyType && !isGlobal
         },
         plugin: {
           ...newProperty.plugin,
diff --git a/openbis_ng_ui/srcTest/js/common/fixture.js b/openbis_ng_ui/srcTest/js/common/fixture.js
index 6f13cefad4c51d684b9d8446e2c2eb3ba6feec25..6cd9060e2f6e803a2401125315bc11eb82bba7cf 100644
--- a/openbis_ng_ui/srcTest/js/common/fixture.js
+++ b/openbis_ng_ui/srcTest/js/common/fixture.js
@@ -32,6 +32,9 @@ ANOTHER_USER_GROUP_DTO.setUsers([ANOTHER_USER_DTO])
 const TEST_PLUGIN_DTO = new openbis.Plugin()
 TEST_PLUGIN_DTO.setName('TEST_PLUGIN')
 
+const ANOTHER_PLUGIN_DTO = new openbis.Plugin()
+ANOTHER_PLUGIN_DTO.setName('ANOTHER_PLUGIN')
+
 const TEST_PROPERTY_TYPE_1_DTO = new openbis.PropertyType()
 TEST_PROPERTY_TYPE_1_DTO.setCode('TEST_PROPERTY_TYPE_1')
 TEST_PROPERTY_TYPE_1_DTO.setPermId(
@@ -158,6 +161,7 @@ export default {
   TEST_USER_GROUP_DTO,
   ANOTHER_USER_GROUP_DTO,
   TEST_PLUGIN_DTO,
+  ANOTHER_PLUGIN_DTO,
   TEST_PROPERTY_TYPE_1_DTO,
   TEST_PROPERTY_TYPE_2_DTO,
   TEST_PROPERTY_TYPE_3_DTO,
diff --git a/openbis_ng_ui/srcTest/js/components/common/form/wrapper/AutocompleterFieldWrapper.js b/openbis_ng_ui/srcTest/js/components/common/form/wrapper/AutocompleterFieldWrapper.js
index 0c723599cdd502c1982d3a7846a321ae64e64b65..8e654ff2d33197fb8c9572772fb7c5c25ed46db0 100644
--- a/openbis_ng_ui/srcTest/js/components/common/form/wrapper/AutocompleterFieldWrapper.js
+++ b/openbis_ng_ui/srcTest/js/components/common/form/wrapper/AutocompleterFieldWrapper.js
@@ -8,4 +8,18 @@ export default class AutocompleterFieldWrapper extends FieldWrapper {
       return false
     }
   }
+  getOptions() {
+    return this.wrapper.prop('options')
+  }
+
+  toJSON() {
+    if (this.wrapper.exists()) {
+      return {
+        ...super.toJSON(),
+        options: this.getOptions()
+      }
+    } else {
+      return null
+    }
+  }
 }
diff --git a/openbis_ng_ui/srcTest/js/components/types/form/TypeFormComponent.test.js b/openbis_ng_ui/srcTest/js/components/types/form/TypeFormComponent.test.js
index c0f600a38386bd107de11857e1a2c328ffb4cc97..63c2bb70c08ba79821166df402a755b3a36af934 100644
--- a/openbis_ng_ui/srcTest/js/components/types/form/TypeFormComponent.test.js
+++ b/openbis_ng_ui/srcTest/js/components/types/form/TypeFormComponent.test.js
@@ -4,6 +4,7 @@ import TypeForm from '@src/js/components/types/form/TypeForm.jsx'
 import TypeFormWrapper from '@srcTest/js/components/types/form/wrapper/TypeFormWrapper.js'
 import TypeFormController from '@src/js/components/types/form/TypeFormController.js'
 import TypeFormFacade from '@src/js/components/types/form/TypeFormFacade'
+import TypeFormPropertyScope from '@src/js/components/types/form/TypeFormPropertyScope.js'
 import objectTypes from '@src/js/common/consts/objectType.js'
 import openbis from '@srcTest/js/services/openbis.js'
 import fixture from '@srcTest/js/common/fixture.js'
@@ -30,6 +31,7 @@ beforeEach(() => {
   facade.loadValidationPlugins.mockReturnValue(Promise.resolve([]))
   facade.loadMaterials.mockReturnValue(Promise.resolve([]))
   facade.loadSamples.mockReturnValue(Promise.resolve([]))
+  facade.loadVocabularies.mockReturnValue(Promise.resolve([]))
   facade.loadVocabularyTerms.mockReturnValue(Promise.resolve([]))
   facade.loadGlobalPropertyTypes.mockReturnValue(Promise.resolve([]))
 })
@@ -43,7 +45,9 @@ describe('TypeFormComponent', () => {
   test('select property global used', testSelectPropertyGlobalUsed)
   test('select section', testSelectSection)
   test('add section', testAddSection)
-  test('add property', testAddProperty)
+  test('add local property', testAddLocalProperty)
+  test('add new global property', testAddNewGlobalProperty)
+  test('add existing global property', testAddExistingGlobalProperty)
   test('change type', testChangeType)
   test('change property', testChangeProperty)
   test('convert property', testConvertProperty)
@@ -223,19 +227,19 @@ async function testLoadExisting() {
 }
 
 async function testSelectPropertyLocalUnused() {
-  await doTestSelectProperty('local', false)
+  await doTestSelectProperty(TypeFormPropertyScope.LOCAL, false)
 }
 
 async function testSelectPropertyLocalUsed() {
-  await doTestSelectProperty('local', true)
+  await doTestSelectProperty(TypeFormPropertyScope.LOCAL, true)
 }
 
 async function testSelectPropertyGlobalUnused() {
-  await doTestSelectProperty('global', false)
+  await doTestSelectProperty(TypeFormPropertyScope.GLOBAL, false)
 }
 
 async function testSelectPropertyGlobalUsed() {
-  await doTestSelectProperty('global', true)
+  await doTestSelectProperty(TypeFormPropertyScope.GLOBAL, true)
 }
 
 async function doTestSelectProperty(scope, used) {
@@ -244,7 +248,9 @@ async function doTestSelectProperty(scope, used) {
 
   const propertyType = new openbis.PropertyType()
   propertyType.setCode(
-    scope === 'global' ? 'GLOBAL_PROPERTY' : 'TEST_TYPE.LOCAL_PROPERTY'
+    scope === TypeFormPropertyScope.GLOBAL
+      ? 'GLOBAL_PROPERTY'
+      : 'TEST_TYPE.LOCAL_PROPERTY'
   )
   propertyType.setLabel('Test Label')
   propertyType.setDescription('Test Description')
@@ -263,7 +269,7 @@ async function doTestSelectProperty(scope, used) {
 
   const messages = []
 
-  if (scope === 'global') {
+  if (scope === TypeFormPropertyScope.GLOBAL) {
     messages.push({
       text:
         'This property is global. Changes will also influence other types where this property is used.',
@@ -480,7 +486,7 @@ async function testAddSection() {
   })
 }
 
-async function testAddProperty() {
+async function testAddLocalProperty() {
   const form = await mountExisting()
 
   form.expectJSON({
@@ -546,7 +552,7 @@ async function testAddProperty() {
         title: 'Property',
         scope: {
           label: 'Scope',
-          value: 'local',
+          value: TypeFormPropertyScope.LOCAL,
           enabled: true,
           mode: 'edit'
         },
@@ -579,6 +585,18 @@ async function testAddProperty() {
           value: null,
           enabled: true,
           mode: 'edit'
+        },
+        visible: {
+          label: 'Visible',
+          value: true,
+          enabled: true,
+          mode: 'edit'
+        },
+        mandatory: {
+          label: 'Mandatory',
+          value: false,
+          enabled: true,
+          mode: 'edit'
         }
       }
     },
@@ -607,6 +625,457 @@ async function testAddProperty() {
   })
 }
 
+async function testAddNewGlobalProperty() {
+  const EXISTING_GLOBAL_PROPERTY = new openbis.PropertyType()
+  EXISTING_GLOBAL_PROPERTY.setCode('EXISTING_GLOBAL_PROPERTY')
+
+  facade.loadGlobalPropertyTypes.mockReturnValue(
+    Promise.resolve([EXISTING_GLOBAL_PROPERTY])
+  )
+  facade.loadDynamicPlugins.mockReturnValue(
+    Promise.resolve([fixture.TEST_PLUGIN_DTO, fixture.ANOTHER_PLUGIN_DTO])
+  )
+
+  const form = await mountNew()
+
+  form.getButtons().getAddSection().click()
+  await form.update()
+
+  form.getButtons().getAddProperty().click()
+  await form.update()
+
+  form
+    .getParameters()
+    .getProperty()
+    .getScope()
+    .change(TypeFormPropertyScope.GLOBAL)
+  await form.update()
+
+  form.getParameters().getProperty().getCode().change('NEW_GLOBAL_PROPERTY')
+  await form.update()
+
+  form.expectJSON({
+    preview: {
+      sections: [
+        {
+          name: null,
+          properties: [
+            {
+              message: {
+                type: 'info',
+                text: 'Please select a data type to display the field preview.'
+              }
+            }
+          ]
+        }
+      ]
+    },
+    parameters: {
+      property: {
+        title: 'Property',
+        scope: {
+          label: 'Scope',
+          value: TypeFormPropertyScope.GLOBAL,
+          enabled: true,
+          mode: 'edit'
+        },
+        code: {
+          label: 'Code',
+          value: 'NEW_GLOBAL_PROPERTY',
+          enabled: true,
+          mode: 'edit',
+          options: [EXISTING_GLOBAL_PROPERTY.getCode()]
+        },
+        dataType: {
+          label: 'Data Type',
+          value: null,
+          enabled: true,
+          mode: 'edit'
+        },
+        label: {
+          label: 'Label',
+          value: null,
+          enabled: true,
+          mode: 'edit'
+        },
+        description: {
+          label: 'Description',
+          value: null,
+          enabled: true,
+          mode: 'edit'
+        },
+        plugin: {
+          label: 'Dynamic Plugin',
+          value: null,
+          enabled: true,
+          mode: 'edit'
+        },
+        visible: {
+          label: 'Visible',
+          value: true,
+          enabled: true,
+          mode: 'edit'
+        },
+        mandatory: {
+          label: 'Mandatory',
+          value: false,
+          enabled: true,
+          mode: 'edit'
+        }
+      }
+    },
+    buttons: {
+      addSection: {
+        enabled: true
+      },
+      addProperty: {
+        enabled: true
+      },
+      remove: {
+        enabled: true
+      },
+      save: {
+        enabled: true
+      },
+      message: {
+        text: 'You have unsaved changes.',
+        type: 'warning'
+      },
+      edit: null,
+      cancel: null
+    }
+  })
+
+  form.getParameters().getProperty().getDataType().change('VARCHAR')
+  form.getParameters().getProperty().getLabel().change('New Label')
+  form.getParameters().getProperty().getDescription().change('New Description')
+  form
+    .getParameters()
+    .getProperty()
+    .getPlugin()
+    .change(fixture.ANOTHER_PLUGIN_DTO.getName())
+  form.getParameters().getProperty().getVisible().change(false)
+  form.getParameters().getProperty().getMandatory().change(true)
+  await form.update()
+
+  form.expectJSON({
+    preview: {
+      sections: [
+        {
+          name: null,
+          properties: [{ code: 'NEW_GLOBAL_PROPERTY' }]
+        }
+      ]
+    },
+    parameters: {
+      property: {
+        title: 'Property',
+        scope: {
+          label: 'Scope',
+          value: TypeFormPropertyScope.GLOBAL,
+          enabled: true,
+          mode: 'edit'
+        },
+        code: {
+          label: 'Code',
+          value: 'NEW_GLOBAL_PROPERTY',
+          enabled: true,
+          mode: 'edit',
+          options: [EXISTING_GLOBAL_PROPERTY.getCode()]
+        },
+        dataType: {
+          label: 'Data Type',
+          value: 'VARCHAR',
+          enabled: true,
+          mode: 'edit'
+        },
+        label: {
+          label: 'Label',
+          value: 'New Label',
+          enabled: true,
+          mode: 'edit'
+        },
+        description: {
+          label: 'Description',
+          value: 'New Description',
+          enabled: true,
+          mode: 'edit'
+        },
+        plugin: {
+          label: 'Dynamic Plugin',
+          value: fixture.ANOTHER_PLUGIN_DTO.getName(),
+          enabled: true,
+          mode: 'edit'
+        },
+        visible: {
+          label: 'Visible',
+          value: false,
+          enabled: true,
+          mode: 'edit'
+        },
+        mandatory: {
+          label: 'Mandatory',
+          value: true,
+          enabled: true,
+          mode: 'edit'
+        }
+      }
+    },
+    buttons: {
+      addSection: {
+        enabled: true
+      },
+      addProperty: {
+        enabled: true
+      },
+      remove: {
+        enabled: true
+      },
+      save: {
+        enabled: true
+      },
+      message: {
+        text: 'You have unsaved changes.',
+        type: 'warning'
+      },
+      edit: null,
+      cancel: null
+    }
+  })
+}
+
+async function testAddExistingGlobalProperty() {
+  const EXISTING_GLOBAL_PROPERTY = new openbis.PropertyType()
+  EXISTING_GLOBAL_PROPERTY.setCode('EXISTING_GLOBAL_PROPERTY')
+  EXISTING_GLOBAL_PROPERTY.setDataType('CONTROLLEDVOCABULARY')
+  EXISTING_GLOBAL_PROPERTY.setVocabulary(fixture.TEST_VOCABULARY_DTO)
+  EXISTING_GLOBAL_PROPERTY.setLabel('Existing Label')
+  EXISTING_GLOBAL_PROPERTY.setDescription('Existing Description')
+
+  facade.loadGlobalPropertyTypes.mockReturnValue(
+    Promise.resolve([EXISTING_GLOBAL_PROPERTY])
+  )
+  facade.loadDynamicPlugins.mockReturnValue(
+    Promise.resolve([fixture.TEST_PLUGIN_DTO, fixture.ANOTHER_PLUGIN_DTO])
+  )
+  facade.loadVocabularies.mockReturnValue(
+    Promise.resolve([fixture.TEST_VOCABULARY_DTO])
+  )
+
+  const form = await mountNew()
+
+  form.getButtons().getAddSection().click()
+  await form.update()
+
+  form.getButtons().getAddProperty().click()
+  await form.update()
+
+  form
+    .getParameters()
+    .getProperty()
+    .getScope()
+    .change(TypeFormPropertyScope.GLOBAL)
+  await form.update()
+
+  form
+    .getParameters()
+    .getProperty()
+    .getCode()
+    .change(EXISTING_GLOBAL_PROPERTY.getCode())
+  await form.update()
+
+  form.expectJSON({
+    preview: {
+      sections: [
+        {
+          name: null,
+          properties: [{ code: EXISTING_GLOBAL_PROPERTY.getCode() }]
+        }
+      ]
+    },
+    parameters: {
+      property: {
+        title: 'Property',
+        scope: {
+          label: 'Scope',
+          value: TypeFormPropertyScope.GLOBAL,
+          enabled: true,
+          mode: 'edit'
+        },
+        code: {
+          label: 'Code',
+          value: EXISTING_GLOBAL_PROPERTY.getCode(),
+          enabled: true,
+          mode: 'edit',
+          options: [EXISTING_GLOBAL_PROPERTY.getCode()]
+        },
+        dataType: {
+          label: 'Data Type',
+          value: EXISTING_GLOBAL_PROPERTY.getDataType(),
+          enabled: true,
+          mode: 'edit'
+        },
+        vocabulary: {
+          label: 'Vocabulary',
+          value: EXISTING_GLOBAL_PROPERTY.vocabulary.getCode(),
+          enabled: false,
+          mode: 'edit'
+        },
+        label: {
+          label: 'Label',
+          value: EXISTING_GLOBAL_PROPERTY.getLabel(),
+          enabled: true,
+          mode: 'edit'
+        },
+        description: {
+          label: 'Description',
+          value: EXISTING_GLOBAL_PROPERTY.getDescription(),
+          enabled: true,
+          mode: 'edit'
+        },
+        plugin: {
+          label: 'Dynamic Plugin',
+          value: null,
+          enabled: true,
+          mode: 'edit'
+        },
+        visible: {
+          label: 'Visible',
+          value: true,
+          enabled: true,
+          mode: 'edit'
+        },
+        mandatory: {
+          label: 'Mandatory',
+          value: false,
+          enabled: true,
+          mode: 'edit'
+        }
+      }
+    },
+    buttons: {
+      addSection: {
+        enabled: true
+      },
+      addProperty: {
+        enabled: true
+      },
+      remove: {
+        enabled: true
+      },
+      save: {
+        enabled: true
+      },
+      message: {
+        text: 'You have unsaved changes.',
+        type: 'warning'
+      },
+      edit: null,
+      cancel: null
+    }
+  })
+
+  form
+    .getParameters()
+    .getProperty()
+    .getPlugin()
+    .change(fixture.ANOTHER_PLUGIN_DTO.getName())
+  form.getParameters().getProperty().getVisible().change(false)
+  form.getParameters().getProperty().getMandatory().change(true)
+  await form.update()
+
+  form.expectJSON({
+    preview: {
+      sections: [
+        {
+          name: null,
+          properties: [{ code: EXISTING_GLOBAL_PROPERTY.getCode() }]
+        }
+      ]
+    },
+    parameters: {
+      property: {
+        title: 'Property',
+        scope: {
+          label: 'Scope',
+          value: TypeFormPropertyScope.GLOBAL,
+          enabled: true,
+          mode: 'edit'
+        },
+        code: {
+          label: 'Code',
+          value: EXISTING_GLOBAL_PROPERTY.getCode(),
+          enabled: true,
+          mode: 'edit',
+          options: [EXISTING_GLOBAL_PROPERTY.getCode()]
+        },
+        dataType: {
+          label: 'Data Type',
+          value: EXISTING_GLOBAL_PROPERTY.getDataType(),
+          enabled: true,
+          mode: 'edit'
+        },
+        vocabulary: {
+          label: 'Vocabulary',
+          value: EXISTING_GLOBAL_PROPERTY.vocabulary.getCode(),
+          enabled: false,
+          mode: 'edit'
+        },
+        label: {
+          label: 'Label',
+          value: EXISTING_GLOBAL_PROPERTY.getLabel(),
+          enabled: true,
+          mode: 'edit'
+        },
+        description: {
+          label: 'Description',
+          value: EXISTING_GLOBAL_PROPERTY.getDescription(),
+          enabled: true,
+          mode: 'edit'
+        },
+        plugin: {
+          label: 'Dynamic Plugin',
+          value: fixture.ANOTHER_PLUGIN_DTO.getName(),
+          enabled: true,
+          mode: 'edit'
+        },
+        visible: {
+          label: 'Visible',
+          value: false,
+          enabled: true,
+          mode: 'edit'
+        },
+        mandatory: {
+          label: 'Mandatory',
+          value: true,
+          enabled: true,
+          mode: 'edit'
+        }
+      }
+    },
+    buttons: {
+      addSection: {
+        enabled: true
+      },
+      addProperty: {
+        enabled: true
+      },
+      remove: {
+        enabled: true
+      },
+      save: {
+        enabled: true
+      },
+      message: {
+        text: 'You have unsaved changes.',
+        type: 'warning'
+      },
+      edit: null,
+      cancel: null
+    }
+  })
+}
+
 async function testChangeType() {
   const form = await mountExisting()