diff --git a/contrib/openldap/core-fd-conf.schema b/contrib/openldap/core-fd-conf.schema
index 32291dc1f04be61a5b19cdef3c28f4cf464c40d6..a27f7f7227403abc842b34acfe58f8d9c4ddeeb3 100644
--- a/contrib/openldap/core-fd-conf.schema
+++ b/contrib/openldap/core-fd-conf.schema
@@ -425,6 +425,13 @@ attributetype ( 1.3.6.1.4.1.38414.8.18.12 NAME 'fdAclTargetFilterLimit'
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
   SINGLE-VALUE )
 
+attributetype ( 1.3.6.1.4.1.38414.8.18.13 NAME 'fdIncrementalModifierStates'
+  DESC 'FusionDirectory - States of the incremental modifier intances, with keys value and date, encoded as JSON'
+  EQUALITY caseExactMatch
+  SUBSTR caseExactSubstringsMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+  SINGLE-VALUE )
+
 # Plugins
 
 attributetype ( 1.3.6.1.4.1.38414.8.19.1 NAME 'fdOGroupRDN'
@@ -610,6 +617,7 @@ objectclass ( 1.3.6.1.4.1.38414.8.2.1 NAME 'fusionDirectoryConf'
     fdTabHook $ fdShells $ fdDefaultShell $ fdDisplayHookOutput $
     fdPluginsMenuBlacklist $ fdManagementConfig $ fdManagementUserConfig $
     fdAclTabOnObjects $ fdDepartmentCategories $ fdAclTargetFilterLimit $
+    fdIncrementalModifierStates $
     fdSslCaCertPath $ fdSslKeyPath $ fdSslCertPath $
     fdCasActivated $ fdCasServerCaCertPath $ fdCasHost $ fdCasPort $ fdCasContext $
     fdLoginMethod
diff --git a/include/class_Lock.inc b/include/class_Lock.inc
index 3b1a110d18ebc91f02bcdbbf7a9efd0f2688658f..0e370eefcf7732b36bb2cce725b5a1f9fb5d4fb0 100644
--- a/include/class_Lock.inc
+++ b/include/class_Lock.inc
@@ -38,7 +38,7 @@ class Lock
    *  \brief Add a lock for object(s)
    *
    * Adds a lock by the specified user for one ore multiple objects.
-   * If the lock for that object already exists, an error is triggered.
+   * If a lock for that object already exists from another user, an error is triggered.
    *
    * \param array $object The object or array of objects to lock
    *
@@ -267,6 +267,34 @@ class Lock
     return $locks;
   }
 
+
+  /*!
+   *  \brief Add a lock for object(s) or fail
+   *
+   * Adds a lock by the specified user for one ore multiple objects.
+   * If the lock for that object already exists, waits a bit and retry.
+   * If a lock cannot be set, throws.
+   *
+   * \param array|string $object The object or array of objects to lock
+   *
+   * \param string $user  The user who shall own the lock
+   *
+   * \param int $retries  how many times we can retry (waiting a second each time)
+   */
+  public static function addOrFail ($object, string $user = NULL, int $retries = 10)
+  {
+    $wait = $retries;
+    while (!empty($locks = Lock::get($object))) {
+      sleep(1);
+
+      /* Oups - timed out */
+      if ($wait-- == 0) {
+        throw new FusionDirectoryException(_('Timeout while waiting for lock!'));
+      }
+    }
+    Lock::add($object, $user);
+  }
+
   /*!
    * \brief Generate a lock message
    *
diff --git a/include/class_templateHandling.inc b/include/class_templateHandling.inc
index 18b382a45ff713d971303fca56e03730f51016d9..1ccf38406a0e87ee8567d0c0391d082408c22144 100644
--- a/include/class_templateHandling.inc
+++ b/include/class_templateHandling.inc
@@ -436,6 +436,11 @@ class templateHandling
     return [$dateObject->format($args[1])];
   }
 
+  /*
+    First parameter is whether the number should always be there or only in case of duplicates (1 or 0, defaults to 0).
+    Second parameter is starting number, defaults to 1.
+    Third parameter is step, defaults to 1.
+  */
   private static function modifierNumber (array $args)
   {
     if (count($args) < 1) {
@@ -462,6 +467,53 @@ class templateHandling
     return $numberGenerator($args[0], $args[1], $args[2]);
   }
 
+  /*
+    Modifier parameters:
+    * id
+    * starting number, defaults to 1.
+    * step, defaults to 1.
+  */
+  private static function modifierIncremental (array $args): array
+  {
+    global $config;
+
+    if (count($args) < 1) {
+      throw new FusionDirectoryException(_('Missing id parameter for incremental modifier'));
+    }
+    if (count($args) < 2) {
+      $args[] = 1;
+    }
+    if (count($args) < 3) {
+      $args[] = 1;
+    }
+    $configDn = CONFIGRDN.$config->current['BASE'];
+    Lock::addOrFail($configDn);
+    $tabObject = objects::open($configDn, 'configuration');
+    $json = $tabObject->getBaseObject()->fdIncrementalModifierStates;
+    if (empty($json)) {
+      $modifierStates = [];
+    } else {
+      $modifierStates = json_decode($json, TRUE);
+    }
+    if (isset($modifierStates[$args[0]])) {
+      $value = $modifierStates[$args[0]]['value'] + $args[2];
+    } else {
+      $value = $args[1];
+    }
+    $modifierStates[$args[0]] = [
+      'value' => $value,
+      'date'  => date('Y-m-d'),
+    ];
+    $tabObject->getBaseObject()->fdIncrementalModifierStates = json_encode($modifierStates);
+    $errors = $tabObject->save();
+    Lock::deleteByObject($configDn);
+    if (!empty($errors)) {
+      throw $errors[0];
+    }
+
+    return [$value];
+  }
+
   private static function modifierTitleCase ($str)
   {
     return [mb_convert_case($str, MB_CASE_TITLE, 'UTF-8')];
@@ -581,6 +633,10 @@ class templateHandling
         // title case
         $result = static::modifierTitleCase($str);
         break;
+      case 'e':
+        // incremental number
+        $result = static::modifierIncremental($args);
+        break;
       default:
         trigger_error("Unkown modifier '$m'");
         $result = [$str];
diff --git a/plugins/config/class_configInLdap.inc b/plugins/config/class_configInLdap.inc
index 456e4d76c72450d6e42c7f11caaa557b6569f74f..8c5bac2cfc27f8b541905cad978e841057d96a38 100644
--- a/plugins/config/class_configInLdap.inc
+++ b/plugins/config/class_configInLdap.inc
@@ -72,6 +72,7 @@ class configInLdap extends simplePlugin
             ['America/New_York']
           ),
           new HiddenAttribute('fusionConfigMd5'),
+          new HiddenAttribute('fdIncrementalModifierStates'),
         ]
       ],
       'core_settings' => [