 .../src/Plugin/DataType/ComputedImageStyleList.php | 92 ++++++++++++++++++++++
 .../image/src/Plugin/DataType/ImageStyle.php       | 54 +++++++++++++
 .../image/src/Plugin/Field/FieldType/ImageItem.php |  7 ++
 .../src/Normalizer/ListNormalizer.php              |  4 +-
 4 files changed, 155 insertions(+), 2 deletions(-)

diff --git a/core/modules/image/src/Plugin/DataType/ComputedImageStyleList.php b/core/modules/image/src/Plugin/DataType/ComputedImageStyleList.php
new file mode 100644
index 0000000..17f7647
--- /dev/null
+++ b/core/modules/image/src/Plugin/DataType/ComputedImageStyleList.php
@@ -0,0 +1,92 @@
+<?php
+
+namespace Drupal\image\Plugin\DataType;
+
+use Drupal\Core\TypedData\Plugin\DataType\ItemList;
+use Drupal\file\FileInterface;
+use Drupal\image\Entity\ImageStyle;
+use Drupal\image\ImageStyleInterface;
+
+/**
+ * List class for \Drupal\image\Plugin\DataType\ImageStyle.
+ *
+ * @ingroup typed_data
+ */
+class ComputedImageStyleList extends ItemList {
+
+  /**
+   * Compute the list property from state.
+   */
+  protected function computedListProperty() {
+    /** @var \Drupal\image\Plugin\Field\FieldType\ImageItem $image_item */
+    $image_item = $this->getParent();
+
+    /** @var \Drupal\file\FileInterface $file */
+    $file = $image_item->entity;
+    $width = $image_item->width;
+    $height = $image_item->height;
+
+    foreach (ImageStyle::loadMultiple() as $style) {
+      $this->list[$style->getName()] = $this->createItem($style->getName(), $this->computeImageStyleMetadata($file, $width, $height, $style));
+    }
+  }
+
+  /**
+   * @param \Drupal\file\FileInterface $file
+   * @param $width
+   * @param $height
+   * @param \Drupal\image\ImageStyleInterface $style
+   * @return array|bool
+   *
+   * @todo rather than returning an array, return a value object that implements CacheableDependencyInterface
+   *
+   * @see \Drupal\image\Entity\ImageStyle::buildUrl
+   * -> tag: config:image.settings
+   *
+   * -> tag: $style->getCacheTags()
+   */
+  protected function computeImageStyleMetadata(FileInterface $file, $width, $height, ImageStyleInterface $style) {
+    $file_uri = $file->getFileUri();
+
+    if (!$style->supportsUri($file_uri)) {
+      return NULL;
+    }
+
+    $dimensions = [
+      'width' => $width,
+      'height' => $height,
+    ];
+    $style->transformDimensions($dimensions, $file_uri);
+
+    return [
+      'url' => file_url_transform_relative($style->buildUrl($file_uri)),
+      'width' => $dimensions['width'],
+      'height' => $dimensions['height'],
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get($index) {
+    $this->computedListProperty();
+    return isset($this->list[$index]) ? $this->list[$index] : NULL;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIterator() {
+    $this->computedListProperty();
+    return parent::getIterator();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue() {
+    $this->computedListProperty();
+    return parent::getValue();
+  }
+
+}
diff --git a/core/modules/image/src/Plugin/DataType/ImageStyle.php b/core/modules/image/src/Plugin/DataType/ImageStyle.php
new file mode 100644
index 0000000..88fd180
--- /dev/null
+++ b/core/modules/image/src/Plugin/DataType/ImageStyle.php
@@ -0,0 +1,54 @@
+<?php
+
+namespace Drupal\image\Plugin\DataType;
+
+use Drupal\Core\TypedData\TypedData;
+
+/**
+ * The image style data type.
+ *
+ * @ingroup typed_data
+ *
+ * @DataType(
+ *   id = "image_styles",
+ *   label = @Translation("Image style URL"),
+ *   list_class = "\Drupal\image\Plugin\DataType\ComputedImageStyleList",
+ * )
+ *
+ * @todo implement CacheableDependencyInterface
+ *
+ * @internal
+ */
+class ImageStyle extends TypedData {
+
+  protected $url = NULL;
+  protected $width = NULL;
+  protected $height = NULL;
+
+  /**
+   * {@inheritdoc}
+   *
+   * @todo receive a value object that implements CacheableDependencyInterface
+   */
+  public function setValue($value, $notify = TRUE) {
+    $this->url = $value['url'];
+    $this->width = $value['width'];
+    $this->height = $value['height'];
+    // Notify the parent of any changes.
+    if ($notify && isset($this->parent)) {
+      $this->parent->onChange($this->name);
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue() {
+    return [
+      'url' => $this->url,
+      'width' => $this->width,
+      'height' => $this->height,
+    ];
+  }
+
+}
diff --git a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
index 9e58ccd..d516a5a 100644
--- a/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
+++ b/core/modules/image/src/Plugin/Field/FieldType/ImageItem.php
@@ -9,6 +9,7 @@
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\StreamWrapper\StreamWrapperInterface;
 use Drupal\Core\TypedData\DataDefinition;
+use Drupal\Core\TypedData\ListDataDefinition;
 use Drupal\file\Entity\File;
 use Drupal\file\Plugin\Field\FieldType\FileItem;
 
@@ -161,6 +162,12 @@ public static function propertyDefinitions(FieldStorageDefinitionInterface $fiel
       ->setLabel(t('Height'))
       ->setDescription(t('The height of the image in pixels.'));
 
+    $properties['image_styles'] = ListDataDefinition::create('image_styles')
+      ->setLabel(t('Image style metadata'))
+      ->setDescription(t('The URL, width and height for this image in every available image style.'))
+      ->setComputed(TRUE)
+      ->setInternal(FALSE);
+
     return $properties;
   }
 
diff --git a/core/modules/serialization/src/Normalizer/ListNormalizer.php b/core/modules/serialization/src/Normalizer/ListNormalizer.php
index 471886e..b486098 100644
--- a/core/modules/serialization/src/Normalizer/ListNormalizer.php
+++ b/core/modules/serialization/src/Normalizer/ListNormalizer.php
@@ -25,8 +25,8 @@ class ListNormalizer extends NormalizerBase {
    */
   public function normalize($object, $format = NULL, array $context = []) {
     $attributes = [];
-    foreach ($object as $fieldItem) {
-      $attributes[] = $this->serializer->normalize($fieldItem, $format, $context);
+    foreach ($object as $key => $value) {
+      $attributes[$key] = $this->serializer->normalize($value, $format, $context);
     }
     return $attributes;
   }
