diff --git a/modules/ui_patterns_legacy/src/PropConverter.php b/modules/ui_patterns_legacy/src/PropConverter.php
index 2691949ad03e7c541ce270615e2fc0a3c21c8252..cbf76ef9878d0dcea175d9e413020688d0a6d016 100644
--- a/modules/ui_patterns_legacy/src/PropConverter.php
+++ b/modules/ui_patterns_legacy/src/PropConverter.php
@@ -51,6 +51,7 @@ class PropConverter {
     $labels = \array_values($setting['options']);
     $prop = [
       'type' => 'array',
+      'uniqueItems' => TRUE,
       'items' => [
         'type' => $this->getEnumType($values),
         'enum' => $values,
diff --git a/src/EnumTrait.php b/src/EnumTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..3d8bbfb16de4a82812a8f41a6afaed6c364ff7d2
--- /dev/null
+++ b/src/EnumTrait.php
@@ -0,0 +1,61 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\ui_patterns;
+
+/**
+ * Trait for plugins (sources and prop types) handling enum values.
+ */
+trait EnumTrait {
+
+  /**
+   * Get form element options from enumeration.
+   */
+  protected function getEnumOptions(array $definition): array {
+    $values = array_combine($definition['enum'], $definition['enum']);
+    foreach ($values as $key => $label) {
+      if (is_string($label)) {
+        $values[$key] = ucwords($label);
+      }
+    }
+    if (!isset($definition['meta:enum'])) {
+      return array_values($values);
+    }
+    $meta = $definition['meta:enum'];
+    // Remove meta:enum items not found in options.
+    $meta = array_intersect_key($meta, $values);
+    foreach ($meta as $value => $label) {
+      $values[$value] = $label;
+    }
+    return $values;
+  }
+
+  /**
+   * Get allowed values from enumeration.
+   */
+  protected function getAllowedValues(array $definition): array {
+    return array_values($this->getEnumOptions($definition));
+  }
+
+  /**
+   * Converts a source value type to enum data type.
+   *
+   * @param string $value
+   *   The stored.
+   * @param array $enum
+   *   The defined enums.
+   *
+   * @return float|int|mixed
+   *   The converted value.
+   */
+  protected function convertValueToEnumType(string $value, array $enum) {
+    return match (TRUE) {
+      in_array($value, $enum, TRUE) => $value,
+      in_array((int) $value, $enum, TRUE)  => (int) $value,
+      in_array((float) $value, $enum, TRUE) => (float) $value,
+      default => $value,
+    };
+  }
+
+}
diff --git a/src/Plugin/UiPatterns/PropType/EnumListPropType.php b/src/Plugin/UiPatterns/PropType/EnumListPropType.php
index 4877f408453530cf514cab85943bc6cda42725ab..b639622eea0fa71433ca6b366da47e15022dac5e 100644
--- a/src/Plugin/UiPatterns/PropType/EnumListPropType.php
+++ b/src/Plugin/UiPatterns/PropType/EnumListPropType.php
@@ -6,6 +6,7 @@ namespace Drupal\ui_patterns\Plugin\UiPatterns\PropType;
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\ui_patterns\Attribute\PropType;
+use Drupal\ui_patterns\EnumTrait;
 use Drupal\ui_patterns\PropTypePluginBase;
 
 /**
@@ -16,28 +17,27 @@ use Drupal\ui_patterns\PropTypePluginBase;
   label: new TranslatableMarkup('List of enums'),
   description: new TranslatableMarkup('Ordered list of predefined string or number items.'),
   default_source: 'checkboxes',
-  schema: ['type' => 'array', 'items' => ['type' => ['string', 'number', 'integer'], 'enum' => []]]
+  schema: ['type' => 'array', 'items' => ['type' => ['string', 'number', 'integer'], 'enum' => []]],
+  priority: 1
 )]
 class EnumListPropType extends PropTypePluginBase {
 
+  use EnumTrait;
+
   /**
    * {@inheritdoc}
    */
   public function getSummary(array $definition): array {
     $summary = parent::getSummary($definition);
-    if (isset($definition['items']['enum']) && !isset($definition['items']['meta:enum'])) {
-      $values = implode(", ", $definition['items']['enum']);
-      $summary[] = $this->t("Values: @values", ["@values" => $values]);
-    }
-    if (isset($definition['items']['enum']) && isset($definition['items']['meta:enum'])) {
-      $values = implode(", ", $definition['items']['meta:enum']);
-      $summary[] = $this->t("Values: @values", ["@values" => $values]);
+    if (isset($definition['items']['enum'])) {
+      $values = implode(", ", $this->getAllowedValues($definition['items']));
+      $summary[] = $this->t("Allowed values: @values", ["@values" => $values]);
     }
-    if (isset($definition['items']['minItems'])) {
-      $summary[] = $this->t("Min items: @length", ["@length" => $definition['items']['minItems']]);
+    if (isset($definition['minItems'])) {
+      $summary[] = $this->t("Min items: @length", ["@length" => $definition['minItems']]);
     }
-    if (isset($definition['items']['maxItems'])) {
-      $summary[] = $this->t("Max items: @length", ["@length" => $definition['items']['maxItems']]);
+    if (isset($definition['maxItems'])) {
+      $summary[] = $this->t("Max items: @length", ["@length" => $definition['maxItems']]);
     }
     return $summary;
   }
diff --git a/src/Plugin/UiPatterns/PropType/EnumPropType.php b/src/Plugin/UiPatterns/PropType/EnumPropType.php
index 8e64c2b6553cbee081bf907f7112f3e187053593..3c143449a844c0d13114fb00b5402952b28958ef 100644
--- a/src/Plugin/UiPatterns/PropType/EnumPropType.php
+++ b/src/Plugin/UiPatterns/PropType/EnumPropType.php
@@ -6,6 +6,7 @@ namespace Drupal\ui_patterns\Plugin\UiPatterns\PropType;
 
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\ui_patterns\Attribute\PropType;
+use Drupal\ui_patterns\EnumTrait;
 use Drupal\ui_patterns\PropTypePluginBase;
 
 /**
@@ -21,16 +22,16 @@ use Drupal\ui_patterns\PropTypePluginBase;
 )]
 class EnumPropType extends PropTypePluginBase {
 
+  use EnumTrait;
+
   /**
    * {@inheritdoc}
    */
   public function getSummary(array $definition): array {
     $summary = parent::getSummary($definition);
-    if (isset($definition['enum']) && !isset($definition['meta:enum'])) {
-      $summary[] = $this->t("Values: @values", ["@values" => implode(", ", $definition['enum'])]);
-    }
-    if (isset($definition['enum']) && isset($definition['meta:enum'])) {
-      $summary[] = $this->t("Values: @values", ["@values" => implode(", ", $definition['meta:enum'])]);
+    if (isset($definition['enum'])) {
+      $values = implode(", ", $this->getAllowedValues($definition));
+      $summary[] = $this->t("Allowed values: @values", ["@values" => $values]);
     }
     return $summary;
   }
diff --git a/src/Plugin/UiPatterns/PropType/EnumSetPropType.php b/src/Plugin/UiPatterns/PropType/EnumSetPropType.php
new file mode 100644
index 0000000000000000000000000000000000000000..58d158be486e29db8ba98abf13bbba6bc5330c98
--- /dev/null
+++ b/src/Plugin/UiPatterns/PropType/EnumSetPropType.php
@@ -0,0 +1,52 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\ui_patterns\Plugin\UiPatterns\PropType;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\ui_patterns\Attribute\PropType;
+use Drupal\ui_patterns\EnumTrait;
+use Drupal\ui_patterns\PropTypePluginBase;
+
+/**
+ * Provides a 'enum_set' PropType.
+ */
+#[PropType(
+  id: 'enum_set',
+  label: new TranslatableMarkup('Set of enums'),
+  description: new TranslatableMarkup('Set of unique predefined string or number items.'),
+  default_source: 'checkboxes',
+  schema: [
+    'type' => 'array',
+    'uniqueItems' => TRUE,
+    'items' => [
+      'type' => ['string', 'number', 'integer'],
+      'enum' => [],
+    ],
+  ],
+  priority: 10
+)]
+class EnumSetPropType extends PropTypePluginBase {
+
+  use EnumTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSummary(array $definition): array {
+    $summary = parent::getSummary($definition);
+    if (isset($definition['items']['enum'])) {
+      $values = implode(", ", $this->getAllowedValues($definition['items']));
+      $summary[] = $this->t("Allowed values: @values", ["@values" => $values]);
+    }
+    if (isset($definition['minItems'])) {
+      $summary[] = $this->t("Min items: @length", ["@length" => $definition['minItems']]);
+    }
+    if (isset($definition['maxItems'])) {
+      $summary[] = $this->t("Max items: @length", ["@length" => $definition['maxItems']]);
+    }
+    return $summary;
+  }
+
+}
diff --git a/src/Plugin/UiPatterns/Source/CheckboxesWidget.php b/src/Plugin/UiPatterns/Source/CheckboxesWidget.php
index 8c5527466d5cb94effd8684fda25ddd9c5b43169..3f6fee4b0d7a660dbfc549072f075b46bd246dc0 100644
--- a/src/Plugin/UiPatterns/Source/CheckboxesWidget.php
+++ b/src/Plugin/UiPatterns/Source/CheckboxesWidget.php
@@ -7,6 +7,7 @@ namespace Drupal\ui_patterns\Plugin\UiPatterns\Source;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\ui_patterns\Attribute\Source;
+use Drupal\ui_patterns\EnumTrait;
 use Drupal\ui_patterns\SourcePluginPropValue;
 
 /**
@@ -16,11 +17,13 @@ use Drupal\ui_patterns\SourcePluginPropValue;
   id: 'checkboxes',
   label: new TranslatableMarkup('Checkboxes'),
   description: new TranslatableMarkup('A set of checkboxes.'),
-  prop_types: ['enum_list'],
+  prop_types: ['enum_set'],
   tags: ['widget']
 )]
 class CheckboxesWidget extends SourcePluginPropValue {
 
+  use EnumTrait;
+
   /**
    * {@inheritdoc}
    */
@@ -38,28 +41,10 @@ class CheckboxesWidget extends SourcePluginPropValue {
     $form['value'] = [
       '#type' => 'checkboxes',
       '#default_value' => $this->getSetting('value') ?? [],
-      "#options" => $this->getOptions(),
+      "#options" => $this->getEnumOptions($this->propDefinition['items']),
     ];
     $this->addRequired($form['value']);
     return $form;
   }
 
-  /**
-   * Get checkboxes options.
-   */
-  protected function getOptions(): array {
-    $options = array_combine($this->propDefinition['items']['enum'], $this->propDefinition['items']['enum']);
-    foreach ($options as $key => $label) {
-      if (is_string($label)) {
-        $options[$key] = ucwords($label);
-      }
-    }
-    if (!isset($this->propDefinition['items']['meta:enum'])) {
-      return $options;
-    }
-    $meta = $this->propDefinition['items']['meta:enum'];
-    // Remove meta:enum items not found in options.
-    return array_intersect_key($meta, $options);
-  }
-
 }
diff --git a/src/Plugin/UiPatterns/Source/EnumSourceTrait.php b/src/Plugin/UiPatterns/Source/EnumSourceTrait.php
deleted file mode 100644
index 8f1a03a0f53cb9cb79f3011ec8139996aa30abe8..0000000000000000000000000000000000000000
--- a/src/Plugin/UiPatterns/Source/EnumSourceTrait.php
+++ /dev/null
@@ -1,32 +0,0 @@
-<?php
-
-declare(strict_types=1);
-
-namespace Drupal\ui_patterns\Plugin\UiPatterns\Source;
-
-/**
- * Trait for sources handling enum values.
- */
-trait EnumSourceTrait {
-
-  /**
-   * Converts a source value type to enum data type.
-   *
-   * @param string $value
-   *   The stored.
-   * @param array $enum
-   *   The defined enums.
-   *
-   * @return float|int|mixed
-   *   The converted value.
-   */
-  protected function convertValueToEnumType(string $value, array $enum) {
-    return match (TRUE) {
-      in_array($value, $enum, TRUE) => $value,
-      in_array((int) $value, $enum, TRUE)  => (int) $value,
-      in_array((float) $value, $enum, TRUE) => (float) $value,
-      default => $value,
-    };
-  }
-
-}
diff --git a/src/Plugin/UiPatterns/Source/SelectWidget.php b/src/Plugin/UiPatterns/Source/SelectWidget.php
index 717a286efb9c61184da809004a91a15440dd5cc1..e593bdfcbfbc60fff2b221dcc16c7698cdac1bfb 100644
--- a/src/Plugin/UiPatterns/Source/SelectWidget.php
+++ b/src/Plugin/UiPatterns/Source/SelectWidget.php
@@ -7,6 +7,7 @@ namespace Drupal\ui_patterns\Plugin\UiPatterns\Source;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\ui_patterns\Attribute\Source;
+use Drupal\ui_patterns\EnumTrait;
 use Drupal\ui_patterns\SourcePluginPropValue;
 
 /**
@@ -21,7 +22,7 @@ use Drupal\ui_patterns\SourcePluginPropValue;
 )]
 class SelectWidget extends SourcePluginPropValue {
 
-  use EnumSourceTrait;
+  use EnumTrait;
 
   /**
    * {@inheritdoc}
@@ -31,7 +32,7 @@ class SelectWidget extends SourcePluginPropValue {
     $form['value'] = [
       '#type' => 'select',
       '#default_value' => $this->getSetting('value'),
-      "#options" => $this->getOptions(),
+      "#options" => $this->getEnumOptions($this->propDefinition),
       "#empty_option" => $this->t("- Select -"),
     ];
     $this->addRequired($form['value']);
@@ -41,24 +42,6 @@ class SelectWidget extends SourcePluginPropValue {
     return $form;
   }
 
-  /**
-   * Get select options.
-   */
-  protected function getOptions(): array {
-    $options = array_combine($this->propDefinition['enum'], $this->propDefinition['enum']);
-    foreach ($options as $key => $label) {
-      if (is_string($label)) {
-        $options[$key] = ucwords($label);
-      }
-    }
-    if (!isset($this->propDefinition['meta:enum'])) {
-      return $options;
-    }
-    $meta = $this->propDefinition['meta:enum'];
-    // Remove meta:enum items not found in options.
-    return array_intersect_key($meta, $options);
-  }
-
   /**
    * {@inheritdoc}
    */
diff --git a/src/Plugin/UiPatterns/Source/SelectsWidget.php b/src/Plugin/UiPatterns/Source/SelectsWidget.php
new file mode 100644
index 0000000000000000000000000000000000000000..3543aae8dcef478565a5b223c2ef3764807dceed
--- /dev/null
+++ b/src/Plugin/UiPatterns/Source/SelectsWidget.php
@@ -0,0 +1,56 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\ui_patterns\Plugin\UiPatterns\Source;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\ui_patterns\Attribute\Source;
+use Drupal\ui_patterns\EnumTrait;
+use Drupal\ui_patterns\SourcePluginPropValue;
+
+/**
+ * Plugin implementation of the source.
+ */
+#[Source(
+  id: 'selects',
+  label: new TranslatableMarkup('Selects'),
+  description: new TranslatableMarkup('A set of select.'),
+  prop_types: ['enum_list'],
+  tags: ['widget']
+)]
+class SelectsWidget extends SourcePluginPropValue {
+
+  use EnumTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPropValue(): mixed {
+    $value = parent::getPropValue() ?? [];
+    $value = is_scalar($value) ? [$value] : $value;
+    return array_values($value);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function settingsForm(array $form, FormStateInterface $form_state): array {
+    $form = parent::settingsForm($form, $form_state);
+    $min = $this->propDefinition['minItems'] ?? 0;
+    $max = $this->propDefinition['maxItems'] ?? 1;
+    foreach (range(0, $max - 1) as $index) {
+      $form['value'][$index] = [
+        '#type' => 'select',
+        '#default_value' => $this->getSetting('value')[$index] ?? NULL,
+        '#options' => $this->getEnumOptions($this->propDefinition['items']),
+        '#title' => '#' . ($index + 1),
+        '#required' => ($index < $min),
+        '#empty_value' => "",
+      ];
+    }
+    return $form;
+  }
+
+}
diff --git a/src/PropTypePluginBase.php b/src/PropTypePluginBase.php
index a28f610a6c9edb3f9f0478a2fcb7527d8aaf6f16..0a5f9582bc67902c55b603d9f31043f85be27c69 100644
--- a/src/PropTypePluginBase.php
+++ b/src/PropTypePluginBase.php
@@ -52,11 +52,8 @@ abstract class PropTypePluginBase extends PluginBase implements PropTypeInterfac
     if (isset($definition['description'])) {
       $summary[] = $definition['description'];
     }
-    if (isset($definition['default']) && is_scalar($definition['default'])) {
-      $summary[] = $this->t("Default: @default", ["@default" => $definition['default']]);
-    }
-    if (isset($definition['default']) && is_array($definition['default'])) {
-      $summary[] = $this->t("Default: @default", ["@default" => implode(", ", $definition['default'])]);
+    if (isset($definition['default'])) {
+      $summary[] = $this->t("Default: @default", ["@default" => json_encode($definition['default'])]);
     }
     if (isset($definition['ui_patterns']['required']) && $definition['ui_patterns']['required']) {
       $summary[] = $this->t("Required");
diff --git a/src/SchemaManager/CompatibilityChecker.php b/src/SchemaManager/CompatibilityChecker.php
index 1293d95d793e3160a890d5835f2deef5b5c64d33..5bb53cca9bb8c56f5e852892a68c320521a9a154 100644
--- a/src/SchemaManager/CompatibilityChecker.php
+++ b/src/SchemaManager/CompatibilityChecker.php
@@ -159,14 +159,17 @@ class CompatibilityChecker {
     if (!isset($checked_schema["items"]) && isset($reference_schema["items"])) {
       return FALSE;
     }
+    if (($reference_schema["uniqueItems"] ?? FALSE) && (!isset($checked_schema["uniqueItems"]) || !$checked_schema["uniqueItems"])) {
+      return FALSE;
+    }
     // https://json-schema.org/understanding-json-schema/reference/array#items
     if (isset($checked_schema["items"]) && isset($reference_schema["items"])) {
       if (!$this->isCompatible($checked_schema["items"], $reference_schema["items"])) {
         return FALSE;
       }
     }
-    // contains, mincontains, maxcontains, length and uniqueness are not managed
-    // yet.
+    // minItems, maxItems, contains, mincontains, maxcontains and length are
+    // not managed yet.
     return TRUE;
   }