diff --git a/core/lib/Drupal/Core/Config/Schema/Sequence.php b/core/lib/Drupal/Core/Config/Schema/Sequence.php
index 630bb50..bce81a9 100644
--- a/core/lib/Drupal/Core/Config/Schema/Sequence.php
+++ b/core/lib/Drupal/Core/Config/Schema/Sequence.php
@@ -89,4 +89,13 @@ public function set($index, $item) {
     return $this;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function filter($callback) {
+    $this->value = array_filter($this->value, $callback);
+    unset($this->elements);
+    return $this;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Field/FieldItemList.php b/core/lib/Drupal/Core/Field/FieldItemList.php
index 56579e4..27305dc 100644
--- a/core/lib/Drupal/Core/Field/FieldItemList.php
+++ b/core/lib/Drupal/Core/Field/FieldItemList.php
@@ -101,11 +101,9 @@ public function getSetting($setting_name) {
    * {@inheritdoc}
    */
   public function filterEmptyItems() {
-    if (isset($this->list)) {
-      $this->list = array_values(array_filter($this->list, function($item) {
-        return !$item->isEmpty();
-      }));
-    }
+    $this->filter(function ($item) {
+      return !$item->isEmpty();
+    });
   }
 
   /**
diff --git a/core/lib/Drupal/Core/TypedData/ListInterface.php b/core/lib/Drupal/Core/TypedData/ListInterface.php
index 4e78b48..65bd43a 100644
--- a/core/lib/Drupal/Core/TypedData/ListInterface.php
+++ b/core/lib/Drupal/Core/TypedData/ListInterface.php
@@ -80,4 +80,16 @@ public function set($index, $item);
    */
   public function first();
 
+  /**
+   * Filters the items in the list using a custom callback.
+   *
+   * @param callable $callback
+   *   The callback to use for filtering. Like with array_filter(), the
+   *   callback is called for each item in the list. Only items for which the
+   *   callback returns TRUE are preserved.
+   *
+   * @return this
+   */
+  public function filter($callback);
+
 }
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php
index 54f3648..f795aa2 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php
@@ -230,6 +230,33 @@ public function isEmpty() {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function filter($callback) {
+    if (isset($this->list)) {
+      $removed = FALSE;
+      // Apply the filter, detecting if some items were actually removed.
+      $this->list = array_filter($this->list, function ($item) use ($callback, &$removed) {
+        if (call_user_func($callback, $item)) {
+          return TRUE;
+        }
+        else {
+          $removed = TRUE;
+        }
+      });
+      if ($removed) {
+        // Rekey the array using array_values().
+        $this->list = array_values($this->list);
+        // Manually update each item's delta.
+        foreach ($this->list as $delta => $item) {
+          $item->setContext($delta, $this);
+        }
+      }
+    }
+    return $this;
+  }
+
+  /**
    * Implements \Drupal\Core\TypedData\ListInterface::onChange().
    */
   public function onChange($delta) {
