diff --git a/core/config/schema/core.entity.schema.yml b/core/config/schema/core.entity.schema.yml
index f6442f7..371f06d 100644
--- a/core/config/schema/core.entity.schema.yml
+++ b/core/config/schema/core.entity.schema.yml
@@ -69,6 +69,7 @@ core.entity_view_display.*.*.*:
     content:
       type: sequence
       label: 'Field formatters'
+      orderby: key
       sequence:
         - type: mapping
           label: 'Field formatter'
diff --git a/core/lib/Drupal/Core/Config/Config.php b/core/lib/Drupal/Core/Config/Config.php
index 51ade6c..b39c64c 100644
--- a/core/lib/Drupal/Core/Config/Config.php
+++ b/core/lib/Drupal/Core/Config/Config.php
@@ -212,8 +212,8 @@ public function save() {
     if ($this->typedConfigManager->hasConfigSchema($this->name)) {
       // Ensure that the schema wrapper has the latest data.
       $this->schemaWrapper = NULL;
-      foreach ($this->data as $key => $value) {
-        $this->data[$key] = $this->castValue($key, $value);
+      foreach (array_keys($this->data) as $key) {
+        $this->data[$key] = $this->castValue($key);
       }
     }
     else {
diff --git a/core/lib/Drupal/Core/Config/Schema/Mapping.php b/core/lib/Drupal/Core/Config/Schema/Mapping.php
index eed1da8..4a25320 100644
--- a/core/lib/Drupal/Core/Config/Schema/Mapping.php
+++ b/core/lib/Drupal/Core/Config/Schema/Mapping.php
@@ -154,4 +154,8 @@ public function onChange($property_name) {
     }
   }
 
+  public function getCastedValue() {
+    return $this->getValue();
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/Schema/Sequence.php b/core/lib/Drupal/Core/Config/Schema/Sequence.php
index bce81a9..eee57c6 100644
--- a/core/lib/Drupal/Core/Config/Schema/Sequence.php
+++ b/core/lib/Drupal/Core/Config/Schema/Sequence.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Config\Schema;
 
 use Drupal\Core\TypedData\ListInterface;
+use Drupal\Core\TypedData\TypedDataInterface;
 
 /**
  * Defines a configuration element of type Sequence.
@@ -21,6 +22,15 @@ class Sequence extends ArrayElement implements ListInterface {
    */
   protected $itemDefinition;
 
+  public function __construct($definition,  $name = NULL, TypedDataInterface $parent = NULL) {
+    parent::__construct($definition, $name, $parent);
+
+    if (!isset($this->definition['orderby'])) {
+      $this->definition['orderby'] = 'none';
+    }
+  }
+
+
   /**
    * {@inheritdoc}
    */
@@ -35,6 +45,20 @@ protected function parse() {
       $data_definition =  $this->buildDataDefinition($definition, $value, $key);
       $elements[$key] = $this->parseElement($key, $value, $data_definition);
     }
+
+    if (isset($data_definition) && $this->definition['orderby'] == 'value' && is_subclass_of($data_definition->getClass(), '\Drupal\Core\TypedData\PrimitiveInterface')) {
+      usort($elements, function ($a, $b) {
+        if ($a->getValue() == $b->getValue()) {
+            return 0;
+        }
+        return ($a->getValue() < $b->getValue()) ? -1 : 1;
+      });
+    }
+
+    if ($this->definition['orderby'] == 'key') {
+      ksort($elements);
+    }
+
     return $elements;
   }
 
@@ -98,4 +122,12 @@ public function filter($callback) {
     return $this;
   }
 
+  public function getCastedValue() {
+    $value = array();
+    foreach ($this->getElements() as $key => $element) {
+      $value[$key] = $element->getCastedValue();
+    }
+    return $value;
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/StorableConfigBase.php b/core/lib/Drupal/Core/Config/StorableConfigBase.php
index 4af470e..39f481f 100644
--- a/core/lib/Drupal/Core/Config/StorableConfigBase.php
+++ b/core/lib/Drupal/Core/Config/StorableConfigBase.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Config;
 
 use Drupal\Component\Utility\String;
+use Drupal\Core\Config\Schema\ArrayElement;
 use Drupal\Core\Config\Schema\Ignore;
 use Drupal\Core\TypedData\PrimitiveInterface;
 use Drupal\Core\TypedData\Type\FloatInterface;
@@ -168,8 +169,6 @@ protected function validateValue($key, $value) {
    *
    * @param string $key
    *   A string that maps to a key within the configuration data.
-   * @param string $value
-   *   Value to associate with the key.
    *
    * @return mixed
    *   The value cast to the type indicated in the schema.
@@ -177,8 +176,9 @@ protected function validateValue($key, $value) {
    * @throws \Drupal\Core\Config\UnsupportedDataTypeConfigException
    *   If the value is unsupported in configuration.
    */
-  protected function castValue($key, $value) {
+  protected function castValue($key) {
     $element = $this->getSchemaWrapper()->get($key);
+    $value = $element->getValue();
     // Do not cast value if it is unknown or defined to be ignored.
     if ($element && ($element instanceof Undefined || $element instanceof Ignore)) {
       // Do validate the value (may throw UnsupportedDataTypeConfigException)
@@ -186,24 +186,22 @@ protected function castValue($key, $value) {
       $this->validateValue($key, $value);
       return $value;
     }
-    if (is_scalar($value) || $value === NULL) {
-      if ($element && $element instanceof PrimitiveInterface) {
-        // Special handling for integers and floats since the configuration
-        // system is primarily concerned with saving values from the Form API
-        // we have to special case the meaning of an empty string for numeric
-        // types. In PHP this would be casted to a 0 but for the purposes of
-        // configuration we need to treat this as a NULL.
-        $empty_value =  $value === '' && ($element instanceof IntegerInterface || $element instanceof FloatInterface);
-
-        if ($value === NULL || $empty_value) {
-          $value = NULL;
-        }
-        else {
-          $value = $element->getCastedValue();
-        }
+    if ($element instanceof PrimitiveInterface) {
+      // Special handling for integers and floats since the configuration
+      // system is primarily concerned with saving values from the Form API
+      // we have to special case the meaning of an empty string for numeric
+      // types. In PHP this would be casted to a 0 but for the purposes of
+      // configuration we need to treat this as a NULL.
+      $empty_value = $value === '' && ($element instanceof IntegerInterface || $element instanceof FloatInterface);
+
+      if ($value === NULL || $empty_value) {
+        $value = NULL;
+      }
+      else {
+        $value = $element->getCastedValue();
       }
     }
-    else {
+    if ($element instanceof ArrayElement) {
       // Throw exception on any non-scalar or non-array value.
       if (!is_array($value)) {
         throw new UnsupportedDataTypeConfigException(String::format('Invalid data type for config element @name:@key', array(
@@ -211,10 +209,7 @@ protected function castValue($key, $value) {
           '@key' => $key,
         )));
       }
-      // Recurse into any nested keys.
-      foreach ($value as $nested_value_key => $nested_value) {
-        $value[$nested_value_key] = $this->castValue($key . '.' . $nested_value_key, $nested_value);
-      }
+      $value = $element->getCastedValue();
     }
     return $value;
   }
diff --git a/core/modules/user/config/schema/user.schema.yml b/core/modules/user/config/schema/user.schema.yml
index 772deea..8396c66 100644
--- a/core/modules/user/config/schema/user.schema.yml
+++ b/core/modules/user/config/schema/user.schema.yml
@@ -131,6 +131,7 @@ user.role.*:
     permissions:
       type: sequence
       label: 'Permissions'
+      orderby: value
       sequence:
         - type: string
           label: 'Permission'
