diff --git a/core/includes/form.inc b/core/includes/form.inc
index 513615c..d6b6141 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -1781,18 +1781,17 @@ function form_builder($form_id, &$element, &$form_state) {
   // Initialize as unprocessed.
   $element['#processed'] = FALSE;
 
-  // Use element defaults.
-  if (isset($element['#type']) && empty($element['#defaults_loaded']) && ($info = element_info($element['#type']))) {
-    // Overlay $info onto $element, retaining preexisting keys in $element.
-    $element += $info;
-    $element['#defaults_loaded'] = TRUE;
+  form_element_info_merge($element);
+
+  // Validate required properties.
+  foreach ($element['#property_validate'] as $property => $callback) {
+    if (call_user_func($calback, $element[$property])) {
+      throw new \UnexpectedValueException(t('Form element @element has a non-valid<code>@property</code property.', array(
+        '@property' => $property,
+        '@element' => $form_id . '[' . implode('][', $element['#array_parents']) . ']',
+      ))); 
+    }
   }
-  // Assign basic defaults common for all form elements.
-  $element += array(
-    '#required' => FALSE,
-    '#attributes' => array(),
-    '#title_display' => 'before',
-  );
 
   // Special handling if we're on the top level form element.
   if (isset($element['#type']) && $element['#type'] == 'form') {
@@ -1851,12 +1850,7 @@ function form_builder($form_id, &$element, &$form_state) {
   // Recurse through all child elements.
   $count = 0;
   foreach (element_children($element) as $key) {
-    // Prior to checking properties of child elements, their default properties
-    // need to be loaded.
-    if (isset($element[$key]['#type']) && empty($element[$key]['#defaults_loaded']) && ($info = element_info($element[$key]['#type']))) {
-      $element[$key] += $info;
-      $element[$key]['#defaults_loaded'] = TRUE;
-    }
+    form_element_info_merge($element[$key]);
 
     // Don't squash an existing tree value.
     if (!isset($element[$key]['#tree'])) {
@@ -4843,6 +4837,46 @@ function _form_set_attributes(&$element, $class = array()) {
 }
 
 /**
+ * Retrieves the default properties for the defined element type.
+ *
+ * @param $type
+ *   An element type as defined by hook_element_info().
+ */
+function form_element_info($type) {
+  $info = element_info($type);
+  // Merge in form-element-specific defaults.
+  $info += array(
+    '#required' => FALSE,
+    '#attributes' => array(),
+    '#title_display' => 'before',
+  );
+  $info['#property_validate'] += array(
+    '#title' => 'strlen',
+  );
+
+  return $info;
+}
+
+/**
+ * Expands a form element with its default values.
+ *
+ * @param array &$element
+ *
+ * @return NULL
+ */
+function form_element_info_merge(array &$element) {
+  if (isset($element['#type']) && empty($element['#defaults_loaded']) {
+    $info = form_element_info($element['#type']);
+    if ($info) {
+      // Overlay $info onto $element, retaining preexisting keys in $element.
+      $element += $info;
+      $element['#defaults_loaded'] = TRUE;
+    }
+  }
+}
+
+
+/**
  * @} End of "defgroup form_api".
  */
 
