diff --git a/core/modules/serialization/serialization.services.yml b/core/modules/serialization/serialization.services.yml
index 8b570c0..06a35b7 100644
--- a/core/modules/serialization/serialization.services.yml
+++ b/core/modules/serialization/serialization.services.yml
@@ -27,11 +27,13 @@ services:
       # Set the priority lower than the hal entity reference field item
       # normalizer, so that we do not replace that for hal_json.
       # @todo Find a better way for this in https://www.drupal.org/node/2575761.
-      - { name: normalizer, priority: 5 }
+      - { name: normalizer, priority: 9 }
   serializer.normalizer.list:
     class: Drupal\serialization\Normalizer\ListNormalizer
     tags:
-      - { name: normalizer }
+      # Priority must be high than serialization.normalizer.field but less than Hal
+      # Field normalizer
+      - { name: normalizer, priority: 9 }
   serializer.normalizer.password_field_item:
       class: Drupal\serialization\Normalizer\NullNormalizer
       arguments: ['Drupal\Core\Field\Plugin\Field\FieldType\PasswordItem']
@@ -74,3 +76,11 @@ services:
     tags:
       - { name: event_subscriber }
     arguments: ['@serializer', '%serializer.formats%']
+  serialization.normalizer.field_item:
+    class: Drupal\serialization\Normalizer\FieldItemNormalizer
+    tags:
+      - { name: normalizer, priority: 8 }
+  serialization.normalizer.field:
+    class: Drupal\serialization\Normalizer\FieldNormalizer
+    tags:
+      - { name: normalizer, priority: 8 }
diff --git a/core/modules/serialization/src/Normalizer/ContentEntityNormalizer.php b/core/modules/serialization/src/Normalizer/ContentEntityNormalizer.php
index 0fb5300..17155be 100644
--- a/core/modules/serialization/src/Normalizer/ContentEntityNormalizer.php
+++ b/core/modules/serialization/src/Normalizer/ContentEntityNormalizer.php
@@ -8,9 +8,7 @@
 class ContentEntityNormalizer extends EntityNormalizer {
 
   /**
-   * The interface or class that this Normalizer supports.
-   *
-   * @var array
+   * {@inheritdoc}
    */
   protected $supportedInterfaceOrClass = ['Drupal\Core\Entity\ContentEntityInterface'];
 
@@ -32,4 +30,27 @@ public function normalize($object, $format = NULL, array $context = array()) {
     return $attributes;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function denormalize($data, $class, $format = NULL, array $context = []) {
+    /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
+    $entity = parent::denormalize($data, $class, $format, $context);
+    foreach ($data as $field_name => $field_data) {
+      $fieldItemList = $entity->get($field_name);
+      // Remove all values that were set as a part of entity creation as the
+      // field values were not denormalized. When passing this field item list
+      // to field denormalizers there should be no values in the field.
+      $fieldItemList->setValue(array());
+      if ($field_data) {
+        // The field instance must be passed in the context so that denormalizer
+        // can update field values. The entity itself does not need to be passed
+        // because nothing except the current field needs to be set.
+        $context['__target_field_instance'] = $fieldItemList;
+        $this->serializer->denormalize($field_data, get_class($fieldItemList), $format, $context);
+      }
+    }
+    return $entity;
+  }
+
 }
diff --git a/core/modules/serialization/src/Normalizer/FieldItemNormalizer.php b/core/modules/serialization/src/Normalizer/FieldItemNormalizer.php
new file mode 100644
index 0000000..866882a
--- /dev/null
+++ b/core/modules/serialization/src/Normalizer/FieldItemNormalizer.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace Drupal\serialization\Normalizer;
+
+use Symfony\Component\Serializer\Exception\InvalidArgumentException;
+use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
+
+/**
+ * Denormalizes field item object structure by updating the entity field values.
+ */
+class FieldItemNormalizer extends ComplexDataNormalizer implements DenormalizerInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $supportedInterfaceOrClass = 'Drupal\Core\Field\FieldItemInterface';
+
+  /**
+   * {@inheritdoc}
+   */
+  public function denormalize($data, $class, $format = NULL, array $context = array()) {
+    if (!isset($context['__target_field_item_instance'])) {
+      throw new InvalidArgumentException('$context[\'__target_field_item_instance\'] must be set to denormalize with the FieldItemNormalizer');
+    }
+    if ($context['__target_field_item_instance']->getParent() === NULL) {
+      throw new InvalidArgumentException('The field item passed in via $context[\'__target_field_item_instance\'] must have a parent set.');
+    }
+
+    /** @var \Drupal\Core\Field\FieldItemInterface $field_item */
+    $field_item = $context['__target_field_item_instance'];
+
+    $field_item->setValue($this->constructValue($data, $context));
+    return $field_item;
+  }
+
+  /**
+   * Build the field item value using the incoming data.
+   *
+   * Most normalizers that extend this class can simply use this method to
+   * construct the denormalized value without having to override denormalize()
+   * and reimplementing its validation logic or its call to set the field value.
+   *
+   * @param mixed $data
+   *   The incoming data for this field item.
+   * @param array $context
+   *   The context passed into the Normalizer.
+   *
+   * @return mixed
+   *   The value to use in Entity::setValue().
+   */
+  protected function constructValue($data, $context) {
+    return $data;
+  }
+
+}
diff --git a/core/modules/serialization/src/Normalizer/FieldNormalizer.php b/core/modules/serialization/src/Normalizer/FieldNormalizer.php
new file mode 100644
index 0000000..ec43550
--- /dev/null
+++ b/core/modules/serialization/src/Normalizer/FieldNormalizer.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Drupal\serialization\Normalizer;
+
+use Drupal\Core\Field\FieldItemListInterface;
+use Symfony\Component\Serializer\Exception\InvalidArgumentException;
+use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
+
+/**
+ * Denormalizes data to Drupal field values.
+ *
+ * This class simply calls denormalize() on the individual FieldItems. The
+ * FieldItem normalizers are responsible for setting the field values for each
+ * item.
+ *
+ * @see \Drupal\serialization\Normalizer\FieldItemNormalizer.
+ */
+class FieldNormalizer extends ListNormalizer implements DenormalizerInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $supportedInterfaceOrClass = FieldItemListInterface::class;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function denormalize($data, $class, $format = NULL, array $context = array()) {
+    if (!isset($context['__target_field_instance'])) {
+      throw new InvalidArgumentException('$context[\'__target_field_instance\'] must be set to denormalize with the FieldNormalizer');
+    }
+    if ($context['__target_field_instance']->getParent() == NULL) {
+      throw new InvalidArgumentException('The field passed in via $context[\'__target_field_instance\'] must have a parent set.');
+    }
+
+    /** @var FieldItemListInterface $items */
+    $items = $context['__target_field_instance'];
+    $item_class = $items->getItemDefinition()->getClass();
+    foreach ($data as $item_data) {
+      // Create a new item and pass it as the target for the unserialization of
+      // $item_data. All items in field should have removed before this method
+      // was called.
+      // @see \Drupal\serialization\Normalizer\ContentEntityNormalizer::denormalize().
+      $context['__target_field_item_instance'] = $items->appendItem();
+      $this->serializer->denormalize($item_data, $item_class, $format, $context);
+    }
+    return $items;
+  }
+
+}
diff --git a/core/modules/serialization/tests/modules/field_normalization_test/field_normalization_test.info.yml b/core/modules/serialization/tests/modules/field_normalization_test/field_normalization_test.info.yml
new file mode 100644
index 0000000..4ba215e
--- /dev/null
+++ b/core/modules/serialization/tests/modules/field_normalization_test/field_normalization_test.info.yml
@@ -0,0 +1,6 @@
+name: 'FieldItem normalization test support'
+type: module
+description: 'Provides test support for fieldItem normalization test support.'
+package: Testing
+version: VERSION
+core: 8.x
diff --git a/core/modules/serialization/tests/modules/field_normalization_test/field_normalization_test.services.yml b/core/modules/serialization/tests/modules/field_normalization_test/field_normalization_test.services.yml
new file mode 100644
index 0000000..4dbbcb0
--- /dev/null
+++ b/core/modules/serialization/tests/modules/field_normalization_test/field_normalization_test.services.yml
@@ -0,0 +1,5 @@
+services:
+  serializer.normalizer.silly_fielditem:
+    class: Drupal\field_normalization_test\Normalization\TextItemSillyNormalizer
+    tags:
+      - { name: normalizer , priority: 20 }
diff --git a/core/modules/serialization/tests/modules/field_normalization_test/src/Normalization/TextItemSillyNormalizer.php b/core/modules/serialization/tests/modules/field_normalization_test/src/Normalization/TextItemSillyNormalizer.php
new file mode 100644
index 0000000..7187bdf
--- /dev/null
+++ b/core/modules/serialization/tests/modules/field_normalization_test/src/Normalization/TextItemSillyNormalizer.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Drupal\field_normalization_test\Normalization;
+
+use Drupal\serialization\Normalizer\FieldItemNormalizer;
+use Drupal\text\Plugin\Field\FieldType\TextItemBase;
+
+/**
+ * A test TextItem normalizer to test denormalization.
+ */
+class TextItemSillyNormalizer extends FieldItemNormalizer {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $supportedInterfaceOrClass = TextItemBase::class;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function normalize($object, $format = NULL, array $context = array()) {
+    $data = parent::normalize($object, $format, $context);
+    $data['value'] .= '::silly_suffix';
+    return $data;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function constructValue($data, $context) {
+    $value = parent::constructValue($data, $context);
+    $value['value']  = str_replace('::silly_suffix', '', $value['value']);
+    return $value;
+  }
+
+}
diff --git a/core/modules/serialization/tests/src/Kernel/FieldItemSerializationTest.php b/core/modules/serialization/tests/src/Kernel/FieldItemSerializationTest.php
new file mode 100644
index 0000000..7d6befa
--- /dev/null
+++ b/core/modules/serialization/tests/src/Kernel/FieldItemSerializationTest.php
@@ -0,0 +1,81 @@
+<?php
+
+namespace Drupal\Tests\serialization\Kernel;
+
+use Drupal\entity_test\Entity\EntityTestMulRev;
+
+/**
+ * Test field level normalization process.
+ *
+ * @group serialization
+ */
+class FieldItemSerializationTest extends NormalizerTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = array('serialization', 'system', 'field', 'entity_test', 'text', 'filter', 'user', 'field_normalization_test');
+
+  /**
+   * The class name of the test class.
+   *
+   * @var string
+   */
+  protected $entityClass = 'Drupal\entity_test\Entity\EntityTestMulRev';
+
+  /**
+   * The test values.
+   *
+   * @var array
+   */
+  protected $values;
+
+  /**
+   * The test entity.
+   *
+   * @var \Drupal\Core\Entity\ContentEntityBase
+   */
+  protected $entity;
+
+  /**
+   * The serializer service.
+   *
+   * @var \Symfony\Component\Serializer\Serializer.
+   */
+  protected $serializer;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    // Create a test entity to serialize.
+    $this->values = array(
+      'name' => $this->randomMachineName(),
+      'field_test_text' => array(
+        'value' => $this->randomMachineName(),
+        'format' => 'full_html',
+      ),
+    );
+    $this->entity = EntityTestMulRev::create($this->values);
+    $this->entity->save();
+
+    $this->serializer = $this->container->get('serializer');
+
+    $this->installConfig(array('field'));
+  }
+
+  /**
+   * Tests normalizing and denormalizing an entity with field item normalizer.
+   */
+  public function testFieldNormalizeDenormalize() {
+    $normalized = $this->serializer->normalize($this->entity, 'json');
+
+    $expected_field_value = $this->entity->field_test_text[0]->getValue()['value'] . '::silly_suffix';
+    $this->assertEquals($expected_field_value, $normalized['field_test_text'][0]['value'], 'Text field item normalized');
+
+    $denormalized = $this->serializer->denormalize($normalized, $this->entityClass, 'json');
+    $this->assertEquals($denormalized->field_test_text[0]->getValue()['value'], $this->entity->field_test_text[0]->getValue()['value'], 'Text field item  denormalized.');
+  }
+
+}
