diff --git a/core/includes/form.inc b/core/includes/form.inc
index c94bc62..b0d8e08 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -2330,27 +2330,23 @@ function form_type_checkboxes_value($element, $input = FALSE) {
  *   this element.
  */
 function form_type_radios_value(&$element, $input = FALSE) {
+  // Radio buttons can have a submitted value or default value of NULL,
+  // indicating that nothing has been selected. However, if NULL is submitted,
+  // _form_builder_handle_input_element() will replace it with an empty string,
+  // which can cause one of the radio buttons to be incorrectly selected (if an
+  // empty string is one of the #options) or the form to fail validation (if it
+  // is not one of the #options). To prevent this, the #has_garbage_value is
+  // set, to signify to the form API that its standard handling of NULL values
+  // should not be used.
+  if (!isset($input) || ($input === FALSE && !isset($element['#default_value']))) {
+    $element['#has_garbage_value'] = TRUE;
+  }
+
+  // Besides the above, the form API's standard value handling is correct for
+  // radios, so it's not necessary to return anything from this function.
+  // However, for clarity (and backwards compatibility) we still ensure that
+  // the value which will be used for the element is returned.
   if ($input !== FALSE) {
-    // There may not be a submitted value for multiple radio buttons, if none of
-    // the options was checked by default. If there is no submitted input value
-    // for this element (NULL), _form_builder_handle_input_element()
-    // automatically attempts to use the #default_value (if set) or an empty
-    // string (''). However, an empty string would fail validation in
-    // _form_validate(), in case it is not contained in the list of allowed
-    // values in #options.
-    if (!isset($input)) {
-      // Signify a garbage value to disable the #default_value handling and take
-      // over NULL as #value.
-      $element['#has_garbage_value'] = TRUE;
-      // There was a user submission so validation is a must. If this element is
-      // #required, then an appropriate error message will be output. While an
-      // optional #type 'radios' does not necessarily make sense from a user
-      // interaction perspective, there may be use-cases for that and it is not
-      // the job of Form API to artificially limit possibilities.
-      $element['#needs_validation'] = TRUE;
-    }
-    // The value stays the same, but the flags above will ensure it is
-    // processed properly.
     return $input;
   }
   elseif (isset($element['#default_value'])) {
@@ -2359,6 +2355,27 @@ function form_type_radios_value(&$element, $input = FALSE) {
 }
 
 /**
+ * Form value callback: Determines the value for a #type radio form element.
+ *
+ * @param $element
+ *   The form element whose value is being populated.
+ * @param $input
+ *   (optional) The incoming input to populate the form element. If FALSE, the
+ *   element's default value is returned. Defaults to FALSE.
+ *
+ * @return
+ *   The data that will appear in the $element_state['values'] collection for
+ *   this element.
+ *
+ * @see form_type_radios_value()
+ */
+function form_type_radio_value(&$element, $input = FALSE) {
+  // A single radio button's value is determined the same way as a set of
+  // radio buttons.
+  return form_type_radios_value($element, $input);
+}
+
+/**
  * Determines the value for a tableselect form element.
  *
  * @param $element
@@ -2805,7 +2822,7 @@ function theme_radio($variables) {
   $element['#attributes']['type'] = 'radio';
   element_set_attributes($element, array('id', 'name', '#return_value' => 'value'));
 
-  if (isset($element['#return_value']) && $element['#value'] !== FALSE && $element['#value'] == $element['#return_value']) {
+  if (isset($element['#return_value']) && isset($element['#value']) && $element['#value'] == $element['#return_value']) {
     $element['#attributes']['checked'] = 'checked';
   }
   _form_set_class($element, array('form-radio'));
@@ -3041,9 +3058,7 @@ function form_process_radios($element) {
         // The key is sanitized in drupal_attributes() during output from the
         // theme function.
         '#return_value' => $key,
-        // Use default or FALSE. A value of FALSE means that the radio button is
-        // not 'checked'.
-        '#default_value' => isset($element['#default_value']) ? $element['#default_value'] : FALSE,
+        '#default_value' => isset($element['#default_value']) ? $element['#default_value'] : NULL,
         '#attributes' => $element['#attributes'],
         '#parents' => $element['#parents'],
         '#id' => drupal_html_id('edit-' . implode('-', $parents_for_id)),
diff --git a/core/modules/field/modules/options/options.module b/core/modules/field/modules/options/options.module
index 3862ba7..5c52fde 100644
--- a/core/modules/field/modules/options/options.module
+++ b/core/modules/field/modules/options/options.module
@@ -106,16 +106,15 @@ function options_field_widget_form(&$form, &$form_state, $field, $instance, $lan
         $default_value = array(key($options));
       }
 
-      // If this is a single-value field, take the first default value, or
-      // default to NULL so that the form element is properly recognized as
-      // not having a default value.
+      // Radio buttons need a scalar value. Therefore, take the first default
+      // value if there is one, or use NULL otherwise (so that the form element
+      // is properly recognized as not having a default value).
       if (!$multiple) {
         $default_value = $default_value ? reset($default_value) : NULL;
       }
 
       $element += array(
         '#type' => $multiple ? 'checkboxes' : 'radios',
-        // Radio buttons need a scalar value.
         '#default_value' => $default_value,
         '#options' => $options,
       );
