diff --git a/core/lib/Drupal/Core/Cache/ConditionalCacheabilityMetadataBubblingTrait.php b/core/lib/Drupal/Core/Cache/ConditionalCacheabilityMetadataBubblingTrait.php
new file mode 100644
index 0000000..4403da4
--- /dev/null
+++ b/core/lib/Drupal/Core/Cache/ConditionalCacheabilityMetadataBubblingTrait.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Drupal\Core\Cache;
+
+/**
+ * Provides bubble function to apply cacheable dependency to render context.
+ *
+ * This trait should be used with great care. It should only be used by classes
+ * that may be used both inside and outside of a render context.
+ * For example:
+ * - Generating URLs for CLI vs for HTTP responses.
+ * - Serializing/normalizing data for scripts vs for HTTP responses.
+ */
+trait ConditionalCacheabilityMetadataBubblingTrait {
+
+  /**
+   * Bubbles cacheability metadata to the current render context.
+   *
+   * This method does not bubble attachments.
+   *
+   * @param \Drupal\Core\Cache\CacheableDependencyInterface $object
+   *   A cacheable dependency object.
+   */
+  protected function bubble(CacheableDependencyInterface $object) {
+    if ($this->renderer()->hasRenderContext()) {
+      $build = [];
+      CacheableMetadata::createFromObject($object)->applyTo($build);
+      $this->renderer()->render($build);
+    }
+  }
+
+  /**
+   * Gets the render service.
+   *
+   * @return \Drupal\Core\Render\RendererInterface
+   *   The renderer.
+   */
+  protected function renderer() {
+    return isset($this->renderer) ? $this->renderer : \Drupal::service('renderer');
+  }
+
+}
diff --git a/core/modules/image/src/ImageServiceProvider.php b/core/modules/image/src/ImageServiceProvider.php
new file mode 100644
index 0000000..24b4a4a
--- /dev/null
+++ b/core/modules/image/src/ImageServiceProvider.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Drupal\image;
+
+use Drupal\Core\DependencyInjection\ContainerBuilder;
+use Drupal\Core\DependencyInjection\ServiceProviderInterface;
+use Drupal\image\Normalizer\ImageItemNormalizer;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * Provides a normalizer service for image field items.
+ */
+class ImageServiceProvider implements ServiceProviderInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function register(ContainerBuilder $container) {
+    $modules = $container->getParameter('container.modules');
+    if (isset($modules['serialization'])) {
+      // Add an ImageItem normalizer.
+      $service_definition = new Definition(ImageItemNormalizer::class, [
+        new Reference('entity_type.manager'),
+      ]);
+      // Priority should be higher than
+      // serializer.normalizer.entity_reference_field_item but lower than
+      // serializer.normalizer.entity_reference_item.hal.
+      $service_definition->addTag('normalizer', ['priority' => 7]);
+      $container->setDefinition('image.normalizer.image_item', $service_definition);
+    }
+  }
+
+}
diff --git a/core/modules/image/src/Normalizer/ImageItemNormalizer.php b/core/modules/image/src/Normalizer/ImageItemNormalizer.php
new file mode 100644
index 0000000..413d637
--- /dev/null
+++ b/core/modules/image/src/Normalizer/ImageItemNormalizer.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace Drupal\image\Normalizer;
+
+use Drupal\Core\Cache\ConditionalCacheabilityMetadataBubblingTrait;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\file\Entity\File;
+use Drupal\image\Entity\ImageStyle;
+use Drupal\image\Plugin\Field\FieldType\ImageItem;
+use Drupal\serialization\Normalizer\EntityReferenceFieldItemNormalizer;
+
+/**
+ * ImageItem normalizer to provide URLs to image styles.
+ */
+class ImageItemNormalizer extends EntityReferenceFieldItemNormalizer {
+
+  use ConditionalCacheabilityMetadataBubblingTrait;
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $supportedInterfaceOrClass = ImageItem::class;
+
+  /**
+   * Constructs an ImageItemNormalizer object.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   */
+  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
+    $this->entityTypeManager = $entity_type_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function normalize($object, $format = NULL, array $context = array()) {
+    $data = parent::normalize($object, $format, $context);
+    if (empty($data['target_id'])) {
+      return $data;
+    }
+    /** @var \Drupal\file\FileInterface $image */
+    $image = File::load($data['target_id']);
+    $uri = $image->getFileUri();
+    /** @var \Drupal\image\ImageStyleInterface[] $styles */
+    $styles = ImageStyle::loadMultiple();
+    $data['image_styles'] = [];
+    foreach ($styles as $id => $style) {
+      $data['image_styles'][$id] = file_url_transform_relative($style->buildUrl($uri));
+      $this->bubble($style);
+    }
+    return $data;
+  }
+
+}
diff --git a/core/modules/image/tests/src/Kernel/Normalizer/ImageFieldItemNormalizerTest.php b/core/modules/image/tests/src/Kernel/Normalizer/ImageFieldItemNormalizerTest.php
new file mode 100644
index 0000000..3cb2cce
--- /dev/null
+++ b/core/modules/image/tests/src/Kernel/Normalizer/ImageFieldItemNormalizerTest.php
@@ -0,0 +1,108 @@
+<?php
+
+namespace Drupal\Tests\image\Kernel\Normalizer;
+
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Render\BubbleableMetadata;
+use Drupal\Core\Render\RenderContext;
+use Drupal\entity_test\Entity\EntityTest;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\file\Entity\File;
+use Drupal\image\Entity\ImageStyle;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * @coversDefaultClass \Drupal\image\Normalizer\ImageItemNormalizer
+ * @group image
+ */
+class ImageFieldItemNormalizerTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['system', 'entity_test', 'serialization', 'image', 'field', 'user', 'file'];
+
+  /**
+   * The serializer.
+   *
+   * @var \Symfony\Component\Serializer\SerializerInterface
+   */
+  protected $serializer;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->serializer = \Drupal::service('serializer');
+
+    $this->installEntitySchema('entity_test');
+    $this->installEntitySchema('user');
+    $this->installEntitySchema('file');
+    $this->installConfig('system');
+    $this->installConfig('image');
+    $this->installSchema('file', ['file_usage']);
+
+    FieldStorageConfig::create(array(
+      'entity_type' => 'entity_test',
+      'field_name' => 'image_test',
+      'type' => 'image',
+      'cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED,
+    ))->save();
+    FieldConfig::create([
+      'entity_type' => 'entity_test',
+      'field_name' => 'image_test',
+      'bundle' => 'entity_test',
+      'settings' => [
+        'file_extensions' => 'jpg',
+      ],
+    ])->save();
+
+    file_unmanaged_copy(\Drupal::root() . '/core/misc/druplicon.png', 'public://example.jpg');
+    $this->image = File::create([
+      'uri' => 'public://example.jpg',
+    ]);
+    $this->image->save();
+    $this->imageFactory = $this->container->get('image.factory');
+  }
+
+  /**
+   * @covers ::normalize
+   */
+  public function testNormalize() {
+    // Create a test entity with the image field set.
+    $original_entity = EntityTest::create();
+    $original_entity->image_test->target_id = $this->image->id();
+    $original_entity->image_test->alt = $alt = $this->randomMachineName();
+    $original_entity->image_test->title = $title = $this->randomMachineName();
+    $original_entity->name->value = $this->randomMachineName();
+    $original_entity->save();
+
+    $entity = clone $original_entity;
+    $context = new RenderContext();
+    $data = $this->container->get('renderer')
+      ->executeInRenderContext($context, function () use ($entity) {
+        return $this->serializer->normalize($entity);
+      });
+    $cacheability = new BubbleableMetadata();
+    $cache_tags = [];
+    /** @var \Drupal\image\ImageStyleInterface $image_style */
+    foreach (ImageStyle::loadMultiple() as $image_style) {
+      $cache_tags = Cache::mergeTags($cache_tags, $image_style->getCacheTags());
+    }
+    $cacheability->setCacheTags($cache_tags);
+
+    $image_style_ids = array_keys($data['image_test'][0]['image_styles']);
+    $expected_image_style_keys = ['large', 'medium', 'thumbnail'];
+    $this->assertEquals($cacheability, $context->pop());
+    $this->assertEquals($expected_image_style_keys, $image_style_ids);
+
+    foreach ($data['image_test'][0]['image_styles'] as $id => $url) {
+      $this->assertNotEmpty(strstr($url, "files/styles/$id/public/example.jpg"));
+    }
+  }
+
+}
