diff --git a/interdiff.30-36.txt b/interdiff.30-36.txt
new file mode 100644
index 0000000..9e0dcbe
--- /dev/null
+++ b/interdiff.30-36.txt
@@ -0,0 +1,21 @@
+diff --git a/token.tokens.inc b/token.tokens.inc
+index dffad3c..821aac1 100644
+--- a/token.tokens.inc
++++ b/token.tokens.inc
+@@ -1887,9 +1887,13 @@ function _field_tokens($type, $tokens, array $data, array $options, BubbleableMe
+ 
+               else {
+                 foreach ($entity->$field_name as $field_item_delta => $field_item) {
+-                  if (isset($field_item->$property_name)) {
+-                    $field_data_arr[] = $field_item->$property_name;
+-                  }
++                  $property_token_data = [
++                    'field_property' => TRUE,
++                    $data['entity_type'] . '-' . $field_name => $entity->$field_name,
++                    'field_name' => $data['entity_type'] . '-' . $field_name,
++                  ];
++                  $field_data_arr += $token_service
++                    ->generate($field_name, [$field_item_delta . ':' . $token => $field_item_delta . ':' . $original], $property_token_data, $options, $bubbleable_metadata);
+                 }
+               }
+               if (isset($field_tokens['array'])) {
diff --git a/token-array-3115486-30.patch b/token-array-3115486-30.patch
new file mode 100755
index 0000000..3937abe
--- /dev/null
+++ b/token-array-3115486-30.patch
@@ -0,0 +1,158 @@
+diff --git a/token.tokens.inc b/token.tokens.inc
+index 7b2e2cf..50f2894 100755
+--- a/token.tokens.inc
++++ b/token.tokens.inc
+@@ -1576,6 +1576,12 @@ function field_token_info_alter(&$info) {
+           'needs-data' => "list<$field_token_name>",
+           'nested' => TRUE,
+         ];
++        $info['types']["array<$field_token_name>"] = [
++          'name' => t('array of @type values', ['@type' => Html::escape($label)]),
++          'description' => t('Tokens for arrays of @type properties.', ['@type' => Html::escape($label)]),
++          'needs-data' => "array<$field_token_name>",
++          'nested' => TRUE,
++        ];
+       }
+ 
+       // Show a different token for each field delta.
+@@ -1587,6 +1593,12 @@ function field_token_info_alter(&$info) {
+             'type' => $field_token_name,
+           ];
+         }
++        $info['tokens']["list<$field_token_name>"]['array'] = [
++          'name' => t('Array of @label property values', ['@label' => Html::escape($label)]),
++          'module' => 'token',
++          'type' => "array<$field_token_name>",
++          'nested' => TRUE,
++        ];
+       }
+ 
+       // Property tokens.
+@@ -1597,6 +1609,16 @@ function field_token_info_alter(&$info) {
+             'description' => $property_definition->getDescription(),
+             'module' => 'token',
+           ];
++          // Allow to fetch an array of primitive properties.
++          if ($cardinality > 1) {
++            $info['tokens']["array<$field_token_name>"][$property] = [
++              'name' => t('Array of @label values', ['@label' => Html::escape($property_definition->getLabel())]),
++              'description' => t('Array of @label values - allows token array manipulations.', ['@label' => Html::escape($property_definition->getLabel())]),
++              'module' => 'token',
++              'type' => "array",
++              'nested' => TRUE,
++            ];
++          }
+         }
+         elseif (($property_definition instanceof DataReferenceDefinitionInterface) && ($property_definition->getTargetDefinition() instanceof EntityDataDefinitionInterface)) {
+           $referenced_entity_type = $property_definition->getTargetDefinition()->getEntityTypeId();
+@@ -1690,6 +1712,7 @@ function field_tokens($type, $tokens, array $data, array $options, BubbleableMet
+     }
+     // Obtain the entity with the correct language.
+     $entity = \Drupal::service('entity.repository')->getTranslationFromContext($entity, $langcode);
++    $array_token = FALSE;
+ 
+     foreach ($tokens as $name => $original) {
+       // For the [entity:field_name] token.
+@@ -1697,10 +1720,12 @@ function field_tokens($type, $tokens, array $data, array $options, BubbleableMet
+         $field_name = $name;
+         $token_name = $name;
+       }
+-      // For [entity:field_name:0], [entity:field_name:0:value] and
+-      // [entity:field_name:value] tokens.
++      // For [entity:field_name:0], [entity:field_name:0:value],
++      // [entity:field_name:value] and [entity:field_name:array:property_name]
++      // tokens.
+       else {
+         [$field_name, $delta] = explode(':', $name, 2);
++        $array_token = (strpos($delta, 'array:') === 0 || $delta === 'array');
+         if (!is_numeric($delta)) {
+           unset($delta);
+         }
+@@ -1717,6 +1742,7 @@ function field_tokens($type, $tokens, array $data, array $options, BubbleableMet
+       if ($entity->get($field_name)->isEmpty()) {
+         continue;
+       }
++      $token_service = \Drupal::token();
+       // Handle [entity:field_name] and [entity:field_name:0] tokens.
+       if ($field_name === $name || isset($delta)) {
+         $view_display = token_get_token_view_display($entity);
+@@ -1754,9 +1780,9 @@ function field_tokens($type, $tokens, array $data, array $options, BubbleableMet
+         $field_output['#token_options'] = $options;
+         $replacements[$original] = \Drupal::service('renderer')->renderPlain($field_output);
+       }
+-      // Handle [entity:field_name:value] and [entity:field_name:0:value]
+-      // tokens.
+-      elseif ($field_tokens = \Drupal::token()->findWithPrefix($tokens, $field_name)) {
++      // Handle [entity:field_name:value], [entity:field_name:0:value] and
++      // [entity:field_name:array:field_property] tokens.
++      elseif ($field_tokens = $token_service->findWithPrefix($tokens, $field_name)) {
+         // With multiple nested tokens for the same field name, this might
+         // match the same field multiple times. Filter out those that have
+         // already been replaced.
+@@ -1776,7 +1802,65 @@ function field_tokens($type, $tokens, array $data, array $options, BubbleableMet
+           // but ensures that the number of replacements do not grow
+           // exponentialy.
+           foreach ($field_tokens as $field_token_key => $field_token_value) {
+-            $replacements += \Drupal::token()->generate($field_name, [$field_token_key => $field_token_value], $property_token_data, $options, $bubbleable_metadata);
++            $replacements += $token_service->generate($field_name, [$field_token_key => $field_token_value], $property_token_data, $options, $bubbleable_metadata);
++          }
++          // Handle array tokens if there are any.
++          if ($array_token) {
++            $property_array_tokens = $token_service->findWithPrefix($field_tokens, 'array');
++            foreach ($property_array_tokens as $token => $original) {
++              $parts = explode(':', $token);
++              $field_data_arr = [];
++              $property_name = $parts[0];
++              // Check if the property is 'entity' and field is an entity reference field.
++              if ($property_name === 'entity' && $entity->$field_name instanceof \Drupal\Core\Field\EntityReferenceFieldItemList) {
++                // If so, replace the sub-token on the referenced entities.
++                // Strip off leading 'entity:' from the sub-token.
++                $token = substr($token, 7);
++                // Check if we have a defined join separator.
++                if (count($parts) > 2 && $parts[count($parts) - 2] === 'join') {
++                  $parts_without_separator = $parts;
++                  // We need to remove the join:separator.
++                  array_splice($parts_without_separator,count($parts_without_separator) - 2, 2);
++                  // And also remote the "entity".
++                  array_splice($parts_without_separator, 0, count($parts_without_separator) - 1);
++                  $token_without_separator = implode(':', $parts_without_separator);
++                  $separator = $parts[count($parts) - 1];
++                }
++                else {
++                  $token_without_separator = $token;
++                }
++                foreach ($entity->$field_name->referencedEntities() as $field_item_delta => $referenced_entity) {
++                  // Generate subtoken using referenced entity type.
++                  $referenced_entity_type = $referenced_entity->getEntityTypeId();
++                  $token_type = $referenced_entity_type === 'taxonomy_term' ? 'term' : $referenced_entity_type;
++                  $subtoken = '[' . $token_type . ':' . $token_without_separator . ']';
++                  $field_data_arr[] = $token_service->replace($subtoken, [
++                    $referenced_entity_type => $referenced_entity,
++                  ], [
++                    'clear' => TRUE,
++                  ]);
++                }
++              }
++
++              else {
++                foreach ($entity->$field_name as $field_item_delta => $field_item) {
++                  if (isset($field_item->$property_name)) {
++                    $field_data_arr[] = $field_item->$property_name;
++                  }
++                }
++              }
++              if (isset($field_tokens['array'])) {
++                $replacements[$field_tokens['array']] = '';
++              }
++              if ($array_tokens = $token_service->findWithPrefix([$token => $original], $parts[0])) {
++                $replacements = array_merge($replacements, $token_service->generate('array', $array_tokens, ['array' => $field_data_arr], $options, $bubbleable_metadata));
++              }
++              else {
++                // If token already had separator, use that one.
++                $default_separator = isset($options['join']) ? [] : ['join' => isset($separator) ? $separator : ','];
++                $replacements[$original] = token_render_array($field_data_arr, $options + $default_separator);
++              }
++            }
+           }
+         }
+       }
diff --git a/token.tokens.inc b/token.tokens.inc
index 209e1d5..821aac1 100644
--- a/token.tokens.inc
+++ b/token.tokens.inc
@@ -1616,6 +1616,12 @@ function _field_token_info_alter(&$info) {
           'needs-data' => "list<$field_token_name>",
           'nested' => TRUE,
         ];
+        $info['types']["array<$field_token_name>"] = [
+          'name' => t('array of @type values', ['@type' => Html::escape($label)]),
+          'description' => t('Tokens for arrays of @type properties.', ['@type' => Html::escape($label)]),
+          'needs-data' => "array<$field_token_name>",
+          'nested' => TRUE,
+        ];
       }
 
       // Show a different token for each field delta.
@@ -1627,6 +1633,12 @@ function _field_token_info_alter(&$info) {
             'type' => $field_token_name,
           ];
         }
+        $info['tokens']["list<$field_token_name>"]['array'] = [
+          'name' => t('Array of @label property values', ['@label' => Html::escape($label)]),
+          'module' => 'token',
+          'type' => "array<$field_token_name>",
+          'nested' => TRUE,
+        ];
       }
 
       // Property tokens.
@@ -1637,6 +1649,16 @@ function _field_token_info_alter(&$info) {
             'description' => $property_definition->getDescription(),
             'module' => 'token',
           ];
+          // Allow to fetch an array of primitive properties.
+          if ($cardinality > 1) {
+            $info['tokens']["array<$field_token_name>"][$property] = [
+              'name' => t('Array of @label values', ['@label' => Html::escape($property_definition->getLabel())]),
+              'description' => t('Array of @label values - allows token array manipulations.', ['@label' => Html::escape($property_definition->getLabel())]),
+              'module' => 'token',
+              'type' => "array",
+              'nested' => TRUE,
+            ];
+          }
         }
         elseif (($property_definition instanceof DataReferenceDefinitionInterface) && ($property_definition->getTargetDefinition() instanceof EntityDataDefinitionInterface)) {
           $referenced_entity_type = $property_definition->getTargetDefinition()->getEntityTypeId();
@@ -1730,6 +1752,7 @@ function _field_tokens($type, $tokens, array $data, array $options, BubbleableMe
     }
     // Obtain the entity with the correct language.
     $entity = \Drupal::service('entity.repository')->getTranslationFromContext($entity, $langcode);
+    $array_token = FALSE;
 
     foreach ($tokens as $name => $original) {
       // For the [entity:field_name] token.
@@ -1737,10 +1760,12 @@ function _field_tokens($type, $tokens, array $data, array $options, BubbleableMe
         $field_name = $name;
         $token_name = $name;
       }
-      // For [entity:field_name:0], [entity:field_name:0:value] and
-      // [entity:field_name:value] tokens.
+      // For [entity:field_name:0], [entity:field_name:0:value],
+      // [entity:field_name:value] and [entity:field_name:array:property_name]
+      // tokens.
       else {
         [$field_name, $delta] = explode(':', $name, 2);
+        $array_token = (strpos($delta, 'array:') === 0 || $delta === 'array');
         if (!is_numeric($delta)) {
           unset($delta);
         }
@@ -1757,6 +1782,7 @@ function _field_tokens($type, $tokens, array $data, array $options, BubbleableMe
       if ($entity->get($field_name)->isEmpty()) {
         continue;
       }
+      $token_service = \Drupal::token();
       // Handle [entity:field_name] and [entity:field_name:0] tokens.
       if ($field_name === $name || isset($delta)) {
         $view_display = token_get_token_view_display($entity);
@@ -1797,9 +1823,9 @@ function _field_tokens($type, $tokens, array $data, array $options, BubbleableMe
         $field_output['#token_options'] = $options;
         $replacements[$original] = \Drupal::service('renderer')->renderPlain($field_output);
       }
-      // Handle [entity:field_name:value] and [entity:field_name:0:value]
-      // tokens.
-      elseif ($field_tokens = \Drupal::token()->findWithPrefix($tokens, $field_name)) {
+      // Handle [entity:field_name:value], [entity:field_name:0:value] and
+      // [entity:field_name:array:field_property] tokens.
+      elseif ($field_tokens = $token_service->findWithPrefix($tokens, $field_name)) {
         // With multiple nested tokens for the same field name, this might
         // match the same field multiple times. Filter out those that have
         // already been replaced.
@@ -1819,7 +1845,69 @@ function _field_tokens($type, $tokens, array $data, array $options, BubbleableMe
           // but ensures that the number of replacements do not grow
           // exponentialy.
           foreach ($field_tokens as $field_token_key => $field_token_value) {
-            $replacements += \Drupal::token()->generate($field_name, [$field_token_key => $field_token_value], $property_token_data, $options, $bubbleable_metadata);
+            $replacements += $token_service->generate($field_name, [$field_token_key => $field_token_value], $property_token_data, $options, $bubbleable_metadata);
+          }
+          // Handle array tokens if there are any.
+          if ($array_token) {
+            $property_array_tokens = $token_service->findWithPrefix($field_tokens, 'array');
+            foreach ($property_array_tokens as $token => $original) {
+              $parts = explode(':', $token);
+              $field_data_arr = [];
+              $property_name = $parts[0];
+              // Check if the property is 'entity' and field is an entity reference field.
+              if ($property_name === 'entity' && $entity->$field_name instanceof \Drupal\Core\Field\EntityReferenceFieldItemList) {
+                // If so, replace the sub-token on the referenced entities.
+                // Strip off leading 'entity:' from the sub-token.
+                $token = substr($token, 7);
+                // Check if we have a defined join separator.
+                if (count($parts) > 2 && $parts[count($parts) - 2] === 'join') {
+                  $parts_without_separator = $parts;
+                  // We need to remove the join:separator.
+                  array_splice($parts_without_separator,count($parts_without_separator) - 2, 2);
+                  // And also remote the "entity".
+                  array_splice($parts_without_separator, 0, count($parts_without_separator) - 1);
+                  $token_without_separator = implode(':', $parts_without_separator);
+                  $separator = $parts[count($parts) - 1];
+                }
+                else {
+                  $token_without_separator = $token;
+                }
+                foreach ($entity->$field_name->referencedEntities() as $field_item_delta => $referenced_entity) {
+                  // Generate subtoken using referenced entity type.
+                  $referenced_entity_type = $referenced_entity->getEntityTypeId();
+                  $token_type = $referenced_entity_type === 'taxonomy_term' ? 'term' : $referenced_entity_type;
+                  $subtoken = '[' . $token_type . ':' . $token_without_separator . ']';
+                  $field_data_arr[] = $token_service->replace($subtoken, [
+                    $referenced_entity_type => $referenced_entity,
+                  ], [
+                    'clear' => TRUE,
+                  ]);
+                }
+              }
+
+              else {
+                foreach ($entity->$field_name as $field_item_delta => $field_item) {
+                  $property_token_data = [
+                    'field_property' => TRUE,
+                    $data['entity_type'] . '-' . $field_name => $entity->$field_name,
+                    'field_name' => $data['entity_type'] . '-' . $field_name,
+                  ];
+                  $field_data_arr += $token_service
+                    ->generate($field_name, [$field_item_delta . ':' . $token => $field_item_delta . ':' . $original], $property_token_data, $options, $bubbleable_metadata);
+                }
+              }
+              if (isset($field_tokens['array'])) {
+                $replacements[$field_tokens['array']] = '';
+              }
+              if ($array_tokens = $token_service->findWithPrefix([$token => $original], $parts[0])) {
+                $replacements = array_merge($replacements, $token_service->generate('array', $array_tokens, ['array' => $field_data_arr], $options, $bubbleable_metadata));
+              }
+              else {
+                // If token already had separator, use that one.
+                $default_separator = isset($options['join']) ? [] : ['join' => isset($separator) ? $separator : ','];
+                $replacements[$original] = token_render_array($field_data_arr, $options + $default_separator);
+              }
+            }
           }
         }
       }
