diff --git a/core/lib/Drupal/Core/Template/Attribute.php b/core/lib/Drupal/Core/Template/Attribute.php
index 945c5bc0d62..181309264e6 100644
--- a/core/lib/Drupal/Core/Template/Attribute.php
+++ b/core/lib/Drupal/Core/Template/Attribute.php
@@ -62,14 +62,7 @@
  * @see \Drupal\Component\Render\PlainTextOutput::renderFromHtml()
  * @see \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols()
  */
-class Attribute implements \ArrayAccess, \IteratorAggregate, MarkupInterface {
-
-  /**
-   * Stores the attribute data.
-   *
-   * @var \Drupal\Core\Template\AttributeValueBase[]
-   */
-  protected $storage = array();
+class Attribute extends \ArrayObject implements MarkupInterface {
 
   /**
    * Constructs a \Drupal\Core\Template\Attribute object.
@@ -77,7 +70,11 @@ class Attribute implements \ArrayAccess, \IteratorAggregate, MarkupInterface {
    * @param array $attributes
    *   An associative array of key-value pairs to be converted to attributes.
    */
-  public function __construct($attributes = array()) {
+  public function __construct($attributes = []) {
+    // Don't naively attach the attribute array, force it through the filters
+    // set in offsetSet
+    parent::__construct([]);
+
     foreach ($attributes as $name => $value) {
       $this->offsetSet($name, $value);
     }
@@ -86,17 +83,8 @@ public function __construct($attributes = array()) {
   /**
    * {@inheritdoc}
    */
-  public function offsetGet($name) {
-    if (isset($this->storage[$name])) {
-      return $this->storage[$name];
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function offsetSet($name, $value) {
-    $this->storage[$name] = $this->createAttributeValue($name, $value);
+    parent::offsetSet( $name, $this->createAttributeValue($name, $value));
   }
 
   /**
@@ -146,20 +134,6 @@ protected function createAttributeValue($name, $value) {
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function offsetUnset($name) {
-    unset($this->storage[$name]);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function offsetExists($name) {
-    return isset($this->storage[$name]);
-  }
-
-  /**
    * Adds classes or merges them on to array of existing CSS classes.
    *
    * @param string|array ...
@@ -170,7 +144,7 @@ public function offsetExists($name) {
   public function addClass() {
     $args = func_get_args();
     if ($args) {
-      $classes = array();
+      $classes = [];
       foreach ($args as $arg) {
         // Merge the values passed in from the classes array.
         // The argument is cast to an array to support comma separated single
@@ -179,13 +153,13 @@ public function addClass() {
       }
 
       // Merge if there are values, just add them otherwise.
-      if (isset($this->storage['class']) && $this->storage['class'] instanceof AttributeArray) {
+      if (isset($this['class']) && $this['class'] instanceof AttributeArray) {
         // Merge the values passed in from the class value array.
-        $classes = array_merge($this->storage['class']->value(), $classes);
-        $this->storage['class']->exchangeArray($classes);
+        $classes = array_merge($this['class']->value(), $classes);
+        $this['class']->exchangeArray($classes);
       }
       else {
-        $this->offsetSet('class', $classes);
+        $this['class'] = $classes;
       }
     }
 
@@ -203,7 +177,7 @@ public function addClass() {
    * @return $this
    */
   public function setAttribute($attribute, $value) {
-    $this->offsetSet($attribute, $value);
+    $this[$attribute] = $value;
 
     return $this;
   }
@@ -222,11 +196,11 @@ public function removeAttribute() {
       // Support arrays or multiple arguments.
       if (is_array($arg)) {
         foreach ($arg as $value) {
-          unset($this->storage[$value]);
+          unset($this[$value]);
         }
       }
       else {
-        unset($this->storage[$arg]);
+        unset($this[$arg]);
       }
     }
 
@@ -243,9 +217,9 @@ public function removeAttribute() {
    */
   public function removeClass() {
     // With no class attribute, there is no need to remove.
-    if (isset($this->storage['class']) && $this->storage['class'] instanceof AttributeArray) {
+    if (isset($this['class']) && $this['class'] instanceof AttributeArray) {
       $args = func_get_args();
-      $classes = array();
+      $classes = [];
       foreach ($args as $arg) {
         // Merge the values passed in from the classes array.
         // The argument is cast to an array to support comma separated single
@@ -255,8 +229,8 @@ public function removeClass() {
 
       // Remove the values passed in from the value array. Use array_values() to
       // ensure that the array index remains sequential.
-      $classes = array_values(array_diff($this->storage['class']->value(), $classes));
-      $this->storage['class']->exchangeArray($classes);
+      $classes = array_values(array_diff($this['class']->value(), $classes));
+      $this['class']->exchangeArray($classes);
     }
     return $this;
   }
@@ -271,8 +245,8 @@ public function removeClass() {
    *   Returns TRUE if the class exists, or FALSE otherwise.
    */
   public function hasClass($class) {
-    if (isset($this->storage['class']) && $this->storage['class'] instanceof AttributeArray) {
-      return in_array($class, $this->storage['class']->value());
+    if (isset($this['class']) && $this['class'] instanceof AttributeArray) {
+      return in_array($class, $this['class']->value());
     }
     else {
       return FALSE;
@@ -285,7 +259,7 @@ public function hasClass($class) {
   public function __toString() {
     $return = '';
     /** @var \Drupal\Core\Template\AttributeValueBase $value */
-    foreach ($this->storage as $name => $value) {
+    foreach ($this as $name => $value) {
       $rendered = $value->render();
       if ($rendered) {
         $return .= ' ' . $rendered;
@@ -302,7 +276,7 @@ public function __toString() {
    */
   public function toArray() {
     $return = [];
-    foreach ($this->storage as $name => $value) {
+    foreach ($this as $name => $value) {
       $return[$name] = $value->value();
     }
 
@@ -313,23 +287,18 @@ public function toArray() {
    * Implements the magic __clone() method.
    */
   public function __clone() {
-    foreach ($this->storage as $name => $value) {
-      $this->storage[$name] = clone $value;
+    foreach ($this as &$value) {
+      $value = clone $value;
     }
   }
 
   /**
-   * {@inheritdoc}
-   */
-  public function getIterator() {
-    return new \ArrayIterator($this->storage);
-  }
-
-  /**
    * Returns the whole array.
+   *
+   * @deprecated use ::getArrayCopy()
    */
   public function storage() {
-    return $this->storage;
+    return $this->getArrayCopy();
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/Template/AttributeTest.php b/core/tests/Drupal/Tests/Core/Template/AttributeTest.php
index 09ec9894dcc..ce945c520ed 100644
--- a/core/tests/Drupal/Tests/Core/Template/AttributeTest.php
+++ b/core/tests/Drupal/Tests/Core/Template/AttributeTest.php
@@ -118,23 +118,27 @@ public function testRemoveAttribute() {
 
     // Single value.
     $attribute->removeAttribute('alt');
-    $this->assertEmpty($attribute['alt']);
+    $this->assertFalse(isset($attribute['alt']));
 
     // Multiple values.
     $attribute->removeAttribute('id', 'src');
-    $this->assertEmpty($attribute['id']);
-    $this->assertEmpty($attribute['src']);
+    $this->assertFalse(isset($attribute['id']));
+    $this->assertFalse(isset($attribute['src']));
 
     // Single value in array.
     $attribute->removeAttribute(['style']);
-    $this->assertEmpty($attribute['style']);
+    $this->assertFalse(isset($attribute['style']));
 
     // Boolean value.
     $attribute->removeAttribute('checked');
-    $this->assertEmpty($attribute['checked']);
+    $this->assertFalse(isset($attribute['checked']));
 
     // Multiple values in array.
     $attribute->removeAttribute(['title', 'value']);
+    $this->assertFalse(isset($attribute['title']));
+    $this->assertFalse(isset($attribute['value']));
+
+    // Now that all values are unset the string of Attribute should be empty.
     $this->assertEmpty((string) $attribute);
 
   }
@@ -149,7 +153,7 @@ public function testAddClasses() {
 
     // Add no class on empty attribute.
     $attribute->addClass();
-    $this->assertEmpty($attribute['class']);
+    $this->assertFalse(isset($attribute['class']));
 
     // Test various permutations of adding values to empty Attribute objects.
     foreach (array(NULL, FALSE, '', []) as $value) {
