diff --git a/Marlin/Marlin.h b/Marlin/Marlin.h
index f54668439f1..7248e7c4f36 100644
--- a/Marlin/Marlin.h
+++ b/Marlin/Marlin.h
@@ -306,8 +306,8 @@ extern float soft_endstop_min[XYZ], soft_endstop_max[XYZ];
   void update_software_endstops(const AxisEnum axis);
 #endif
 
+#define MAX_COORDINATE_SYSTEMS 9
 #if ENABLED(CNC_COORDINATE_SYSTEMS)
-  #define MAX_COORDINATE_SYSTEMS 9
   extern float coordinate_system[MAX_COORDINATE_SYSTEMS][XYZ];
   bool select_coordinate_system(const int8_t _new);
 #endif
diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index b7454324766..834ae2c49ef 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -9837,6 +9837,18 @@ inline void gcode_M502() {
   }
 #endif
 
+#if ENABLED(EEPROM_SETTINGS)
+  /**
+   * M504: Validate EEPROM Contents
+   */
+  inline void gcode_M504() {
+    if (settings.validate()) {
+      SERIAL_ECHO_START();
+      SERIAL_ECHOLNPGM("EEPROM OK");
+    }
+  }
+#endif
+
 #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
 
   /**
@@ -12050,6 +12062,9 @@ void process_parsed_command() {
       #if DISABLED(DISABLE_M503)
         case 503: gcode_M503(); break;                            // M503: Report Settings (in SRAM)
       #endif
+      #if ENABLED(EEPROM_SETTINGS)
+        case 504: gcode_M504(); break;                            // M504: Validate EEPROM
+      #endif
 
       #if ENABLED(ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
         case 540: gcode_M540(); break;                            // M540: Set Abort on Endstop Hit for SD Printing
diff --git a/Marlin/configuration_store.cpp b/Marlin/configuration_store.cpp
index e6bf62ec33f..e064ebaf7d8 100644
--- a/Marlin/configuration_store.cpp
+++ b/Marlin/configuration_store.cpp
@@ -36,164 +36,15 @@
  *
  */
 
+// Change EEPROM version if the structure changes
 #define EEPROM_VERSION "V48"
-
-// Change EEPROM version if these are changed:
 #define EEPROM_OFFSET 100
 
-/**
- * V48 EEPROM Layout:
- *
- *  100  Version                                    (char x4)
- *  104  EEPROM CRC16                               (uint16_t)
- *
- *  106            E_STEPPERS                       (uint8_t)
- *  107  M92 XYZE  planner.axis_steps_per_mm        (float x4 ... x8) + 64
- *  123  M203 XYZE planner.max_feedrate_mm_s        (float x4 ... x8) + 64
- *  139  M201 XYZE planner.max_acceleration_mm_per_s2 (uint32_t x4 ... x8) + 64
- *  155  M204 P    planner.acceleration             (float)
- *  159  M204 R    planner.retract_acceleration     (float)
- *  163  M204 T    planner.travel_acceleration      (float)
- *  167  M205 S    planner.min_feedrate_mm_s        (float)
- *  171  M205 T    planner.min_travel_feedrate_mm_s (float)
- *  175  M205 B    planner.min_segment_time_us      (ulong)
- *  179  M205 X    planner.max_jerk[X_AXIS]         (float)
- *  183  M205 Y    planner.max_jerk[Y_AXIS]         (float)
- *  187  M205 Z    planner.max_jerk[Z_AXIS]         (float)
- *  191  M205 E    planner.max_jerk[E_AXIS]         (float)
- *  195  M206 XYZ  home_offset                      (float x3)
- *  207  M218 XYZ  hotend_offset                    (float x3 per additional hotend) +16
- *
- * Global Leveling:                                 4 bytes
- *  219            z_fade_height                    (float)
- *
- * MESH_BED_LEVELING:                               43 bytes
- *  223  M420 S    planner.leveling_active          (bool)
- *  224            mbl.z_offset                     (float)
- *  228            GRID_MAX_POINTS_X                (uint8_t)
- *  229            GRID_MAX_POINTS_Y                (uint8_t)
- *  230 G29 S3 XYZ z_values[][]                     (float x9, up to float x81) +288
- *
- * HAS_BED_PROBE:                                   4 bytes
- *  266  M851      zprobe_zoffset                   (float)
- *
- * ABL_PLANAR:                                      36 bytes
- *  270            planner.bed_level_matrix         (matrix_3x3 = float x9)
- *
- * AUTO_BED_LEVELING_BILINEAR:                      46 bytes
- *  306            GRID_MAX_POINTS_X                (uint8_t)
- *  307            GRID_MAX_POINTS_Y                (uint8_t)
- *  308            bilinear_grid_spacing            (int x2)
- *  312  G29 L F   bilinear_start                   (int x2)
- *  316            z_values[][]                     (float x9, up to float x256) +988
- *
- * AUTO_BED_LEVELING_UBL:                           2 bytes
- *  352  G29 A     planner.leveling_active          (bool)
- *  353  G29 S     ubl.storage_slot                 (int8_t)
- *
- * DELTA:                                           44 bytes
- *  354  M666 H    delta_height                     (float)
- *  358  M666 XYZ  delta_endstop_adj                (float x3)
- *  370  M665 R    delta_radius                     (float)
- *  374  M665 L    delta_diagonal_rod               (float)
- *  378  M665 S    delta_segments_per_second        (float)
- *  382  M665 B    delta_calibration_radius         (float)
- *  386  M665 X    delta_tower_angle_trim[A]        (float)
- *  390  M665 Y    delta_tower_angle_trim[B]        (float)
- *  394  M665 Z    delta_tower_angle_trim[C]        (float)
- *
- * [XYZ]_DUAL_ENDSTOPS:                             12 bytes
- *  354  M666 X    x_endstop_adj                    (float)
- *  358  M666 Y    y_endstop_adj                    (float)
- *  362  M666 Z    z_endstop_adj                    (float)
- *
- * ULTIPANEL:                                       6 bytes
- *  398  M145 S0 H lcd_preheat_hotend_temp          (int x2)
- *  402  M145 S0 B lcd_preheat_bed_temp             (int x2)
- *  406  M145 S0 F lcd_preheat_fan_speed            (int x2)
- *
- * PIDTEMP:                                         82 bytes
- *  410  M301 E0 PIDC  Kp[0], Ki[0], Kd[0], Kc[0]   (float x4)
- *  426  M301 E1 PIDC  Kp[1], Ki[1], Kd[1], Kc[1]   (float x4)
- *  442  M301 E2 PIDC  Kp[2], Ki[2], Kd[2], Kc[2]   (float x4)
- *  458  M301 E3 PIDC  Kp[3], Ki[3], Kd[3], Kc[3]   (float x4)
- *  474  M301 E4 PIDC  Kp[3], Ki[3], Kd[3], Kc[3]   (float x4)
- *  490  M301 L        lpq_len                      (int)
- *
- * PIDTEMPBED:                                      12 bytes
- *  492  M304 PID  bedKp, .bedKi, .bedKd            (float x3)
- *
- * DOGLCD:                                          2 bytes
- *  504  M250 C    lcd_contrast                     (uint16_t)
- *
- * FWRETRACT:                                       33 bytes
- *  506  M209 S    autoretract_enabled              (bool)
- *  507  M207 S    retract_length                   (float)
- *  511  M207 F    retract_feedrate_mm_s            (float)
- *  515  M207 Z    retract_zlift                    (float)
- *  519  M208 S    retract_recover_length           (float)
- *  523  M208 F    retract_recover_feedrate_mm_s    (float)
- *  527  M207 W    swap_retract_length              (float)
- *  531  M208 W    swap_retract_recover_length      (float)
- *  535  M208 R    swap_retract_recover_feedrate_mm_s (float)
- *
- * Volumetric Extrusion:                            21 bytes
- *  539  M200 D    parser.volumetric_enabled        (bool)
- *  540  M200 T D  planner.filament_size            (float x5) (T0..4)
- *
- * HAS_TRINAMIC:                                    22 bytes
- *  560  M906 X    Stepper X current                (uint16_t)
- *  562  M906 Y    Stepper Y current                (uint16_t)
- *  564  M906 Z    Stepper Z current                (uint16_t)
- *  566  M906 X2   Stepper X2 current               (uint16_t)
- *  568  M906 Y2   Stepper Y2 current               (uint16_t)
- *  570  M906 Z2   Stepper Z2 current               (uint16_t)
- *  572  M906 E0   Stepper E0 current               (uint16_t)
- *  574  M906 E1   Stepper E1 current               (uint16_t)
- *  576  M906 E2   Stepper E2 current               (uint16_t)
- *  578  M906 E3   Stepper E3 current               (uint16_t)
- *  580  M906 E4   Stepper E4 current               (uint16_t)
- *
- * SENSORLESS_HOMING:                               4 bytes
- *  582  M914 X    Stepper X and X2 threshold       (int16_t)
- *  584  M914 Y    Stepper Y and Y2 threshold       (int16_t)
- *
- * LIN_ADVANCE:                                     8 bytes
- *  586  M900 K    extruder_advance_k               (float)
- *  590  M900 WHD  advance_ed_ratio                 (float)
- *
- * HAS_MOTOR_CURRENT_PWM:
- *  594  M907 X    Stepper XY current               (uint32_t)
- *  598  M907 Z    Stepper Z current                (uint32_t)
- *  602  M907 E    Stepper E current                (uint32_t)
- *
- * CNC_COORDINATE_SYSTEMS:                          108 bytes
- *  606  G54-G59.3 coordinate_system                (float x 27)
- *
- * SKEW_CORRECTION:                                 12 bytes
- *  714  M852 I    planner.xy_skew_factor           (float)
- *  718  M852 J    planner.xz_skew_factor           (float)
- *  722  M852 K    planner.yz_skew_factor           (float)
- *
- * ADVANCED_PAUSE_FEATURE:                          40 bytes
- *  726  M603 T U  filament_change_unload_length    (float x 5) (T0..4)
- *  746  M603 T L  filament_change_load_length      (float x 5) (T0..4)
- *
- *  766                                   Minimum end-point
- * 2295 (766 + 208 + 36 + 9 + 288 + 988)  Maximum end-point
- *
- * ========================================================================
- * meshes_begin (between max and min end-point, directly above)
- * -- MESHES --
- * meshes_end
- * -- MAT (Mesh Allocation Table) --                128 bytes (placeholder size)
- * mat_end = E2END (0xFFF)
- *
- */
+// Check the integrity of data offsets.
+// Can be disabled for production build.
+//#define DEBUG_EEPROM_READWRITE
+
 #include "configuration_store.h"
-
-MarlinSettings settings;
-
 #include "Marlin.h"
 #include "language.h"
 #include "endstops.h"
@@ -202,6 +53,7 @@ MarlinSettings settings;
 #include "ultralcd.h"
 #include "stepper.h"
 #include "gcode.h"
+#include "vector_3.h"
 
 #if ENABLED(MESH_BED_LEVELING)
   #include "mesh_bed_leveling.h"
@@ -219,17 +71,202 @@ MarlinSettings settings;
   #include "fwretract.h"
 #endif
 
+typedef struct PID { float Kp, Ki, Kd; } PID;
+typedef struct PIDC { float Kp, Ki, Kd, Kc; } PIDC;
+
+/**
+ * Current EEPROM Layout
+ *
+ * Keep this data structure up to date so
+ * EEPROM size is known at compile time!
+ */
+typedef struct SettingsDataStruct {
+  char      version[4];                                 // Vnn\0
+  uint16_t  crc;                                        // Data Checksum
+
+  //
+  // DISTINCT_E_FACTORS
+  //
+  uint8_t   esteppers;                                  // XYZE_N - XYZ
+
+  float     planner_axis_steps_per_mm[XYZE_N],          // M92 XYZE   planner.axis_steps_per_mm[XYZE_N]
+            planner_max_feedrate_mm_s[XYZE_N];          // M203 XYZE  planner.max_feedrate_mm_s[XYZE_N]
+  uint32_t  planner_max_acceleration_mm_per_s2[XYZE_N]; // M201 XYZE  planner.max_acceleration_mm_per_s2[XYZE_N]
+  float     planner_acceleration,                       // M204 P     planner.acceleration
+            planner_retract_acceleration,               // M204 R     planner.retract_acceleration
+            planner_travel_acceleration,                // M204 T     planner.travel_acceleration
+            planner_min_feedrate_mm_s,                  // M205 S     planner.min_feedrate_mm_s
+            planner_min_travel_feedrate_mm_s;           // M205 T     planner.min_travel_feedrate_mm_s
+  uint32_t  planner_min_segment_time_us;                // M205 B     planner.min_segment_time_us
+  float     planner_max_jerk[XYZE];                     // M205 XYZE  planner.max_jerk[XYZE]
+
+  float home_offset[XYZ];                               // M206 XYZ
+
+  #if HOTENDS > 1
+    float hotend_offset[XYZ][HOTENDS - 1];              // M218 XYZ
+  #endif
+
+  //
+  // ENABLE_LEVELING_FADE_HEIGHT
+  //
+  float planner_z_fade_height;                          // M420 Zn  planner.z_fade_height
+
+  //
+  // MESH_BED_LEVELING
+  //
+  bool mbl_has_mesh;                                    // mbl.has_mesh
+  float mbl_z_offset;                                   // mbl.z_offset
+  uint8_t mesh_num_x, mesh_num_y;                       // GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y
+  #if ENABLED(MESH_BED_LEVELING)
+    float mbl_z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; // mbl.z_values
+  #else
+    float mbl_z_values[3][3];
+  #endif
+
+  //
+  // HAS_BED_PROBE
+  //
+  float zprobe_zoffset;                                 // M851 Z
+
+  //
+  // ABL_PLANAR
+  //
+  matrix_3x3 planner_bed_level_matrix;                  // planner.bed_level_matrix
+
+  //
+  // AUTO_BED_LEVELING_BILINEAR
+  //
+  uint8_t grid_max_x, grid_max_y;                       // GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y
+  int bilinear_grid_spacing[2],
+      bilinear_start[2];                                // G29 L F
+  #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
+    float z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; // G29
+  #else
+    float z_values[3][3];
+  #endif
+
+  //
+  // AUTO_BED_LEVELING_UBL
+  //
+  bool planner_leveling_active;                         // M420 S  planner.leveling_active
+  int8_t ubl_storage_slot;                              // ubl.storage_slot
+
+  //
+  // DELTA / [XYZ]_DUAL_ENDSTOPS
+  //
+  #if ENABLED(DELTA)
+    float delta_height,                                 // M666 H
+          delta_endstop_adj[ABC],                       // M666 XYZ
+          delta_radius,                                 // M665 R
+          delta_diagonal_rod,                           // M665 L
+          delta_segments_per_second,                    // M665 S
+          delta_calibration_radius,                     // M665 B
+          delta_tower_angle_trim[ABC];                  // M665 XYZ
+  #elif ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
+    float x_endstop_adj,                                // M666 X
+          y_endstop_adj,                                // M666 Y
+          z_endstop_adj;                                // M666 Z
+    float xyz_dual_reserved[8];
+  #else
+    float xyz_dual_placeholder[11];
+  #endif
+
+  //
+  // ULTIPANEL
+  //
+  int lcd_preheat_hotend_temp[2],                       // M145 S0 H
+      lcd_preheat_bed_temp[2],                          // M145 S0 B
+      lcd_preheat_fan_speed[2];                         // M145 S0 F
+
+  //
+  // PIDTEMP
+  //
+  PIDC hotendPID[MAX_EXTRUDERS];                        // M301 En PIDC / M303 En U
+
+  int lpq_len;                                          // M301 L
+
+  //
+  // PIDTEMPBED
+  //
+  PID bedPID;                                           // M304 PID / M303 E-1 U
+
+  //
+  // HAS_LCD_CONTRAST
+  //
+  uint16_t lcd_contrast;                                // M250 C
+
+  //
+  // FWRETRACT
+  //
+  bool autoretract_enabled;                             // M209 S
+  float retract_length,                                 // M207 S
+        retract_feedrate_mm_s,                          // M207 F
+        retract_zlift,                                  // M207 Z
+        retract_recover_length,                         // M208 S
+        retract_recover_feedrate_mm_s,                  // M208 F
+        swap_retract_length,                            // M207 W
+        swap_retract_recover_length,                    // M208 W
+        swap_retract_recover_feedrate_mm_s;             // M208 R
+
+  //
+  // !NO_VOLUMETRIC
+  //
+  bool parser_volumetric_enabled;                       // M200 D  parser.volumetric_enabled
+  float planner_filament_size[MAX_EXTRUDERS];           // M200 T D  planner.filament_size[]
+
+  //
+  // HAS_TRINAMIC
+  //
+  uint16_t tmc_stepper_current[11];                     // M906 X Y Z X2 Y2 Z2 E0 E1 E2 E3 E4
+  int16_t tmc_sgt[2];                                   // M914 X Y
+
+  //
+  // LIN_ADVANCE
+  //
+  float planner_extruder_advance_k,                     // M900 K    planner.extruder_advance_k
+        planner_advance_ed_ratio;                       // M900 WHD  planner.advance_ed_ratio
+
+  //
+  // HAS_MOTOR_CURRENT_PWM
+  //
+  uint32_t motor_current_setting[XYZ];                  // M907 X Z E
+
+  //
+  // CNC_COORDINATE_SYSTEMS
+  //
+  float coordinate_system[MAX_COORDINATE_SYSTEMS][XYZ]; // G54-G59.3
+
+  //
+  // SKEW_CORRECTION
+  //
+  float planner_xy_skew_factor,                         // M852 I  planner.xy_skew_factor
+        planner_xz_skew_factor,                         // M852 J  planner.xz_skew_factor
+        planner_yz_skew_factor;                         // M852 K  planner.yz_skew_factor
+
+  //
+  // ADVANCED_PAUSE_FEATURE
+  //
+  float filament_change_unload_length[MAX_EXTRUDERS],   // M603 T U
+        filament_change_load_length[MAX_EXTRUDERS];     // M603 T L
+
+} SettingsData;
+
+MarlinSettings settings;
+
 #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
   extern void refresh_bed_level();
 #endif
 
+uint16_t MarlinSettings::datasize() { return sizeof(SettingsData); }
+
+/**
+ * Post-process after Retrieve or Reset
+ */
+
 #if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
   float new_z_fade_height;
 #endif
 
-/**
- * Post-process after Retrieve or Reset
- */
 void MarlinSettings::postprocess() {
   const float oldpos[] = { current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] };
 
@@ -287,18 +324,25 @@ void MarlinSettings::postprocess() {
   #define EEPROM_SKIP(VAR) eeprom_index += sizeof(VAR)
   #define EEPROM_WRITE(VAR) write_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc)
   #define EEPROM_READ(VAR) read_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc)
-  #define EEPROM_ASSERT(TST,ERR) if (!(TST)) do{ SERIAL_ERROR_START(); SERIAL_ERRORLNPGM(ERR); eeprom_read_error = true; }while(0)
+  #define EEPROM_READ_ALWAYS(VAR) read_data(eeprom_index, (uint8_t*)&VAR, sizeof(VAR), &working_crc, true)
+  #define EEPROM_ASSERT(TST,ERR) if (!(TST)) do{ SERIAL_ERROR_START(); SERIAL_ERRORLNPGM(ERR); eeprom_error = true; }while(0)
+
+  #if ENABLED(DEBUG_EEPROM_READWRITE)
+    #define _FIELD_TEST(FIELD)                                          \
+      EEPROM_ASSERT(                                                    \
+        eeprom_error || eeprom_index == offsetof(SettingsData, FIELD),  \
+        "Field " STRINGIFY(FIELD) " mismatch."                          \
+      )
+  #else
+    #define _FIELD_TEST(FIELD) NOOP
+  #endif
 
   const char version[4] = EEPROM_VERSION;
 
-  bool MarlinSettings::eeprom_error;
-
-  #if ENABLED(AUTO_BED_LEVELING_UBL)
-    int16_t MarlinSettings::meshes_begin;
-  #endif
+  bool MarlinSettings::eeprom_error, MarlinSettings::validating;
 
   void MarlinSettings::write_data(int &pos, const uint8_t *value, uint16_t size, uint16_t *crc) {
-    if (eeprom_error) return;
+    if (eeprom_error) { pos += size; return; }
     while (size--) {
       uint8_t * const p = (uint8_t * const)pos;
       uint8_t v = *value;
@@ -319,17 +363,26 @@ void MarlinSettings::postprocess() {
     };
   }
 
-  void MarlinSettings::read_data(int &pos, uint8_t* value, uint16_t size, uint16_t *crc) {
-    if (eeprom_error) return;
+  void MarlinSettings::read_data(int &pos, uint8_t* value, uint16_t size, uint16_t *crc, const bool force/*=false*/) {
+    if (eeprom_error) { pos += size; return; }
     do {
       uint8_t c = eeprom_read_byte((unsigned char*)pos);
-      *value = c;
+      if (!validating || force) *value = c;
       crc16(crc, &c, 1);
       pos++;
       value++;
     } while (--size);
   }
 
+  bool MarlinSettings::size_error(const uint16_t size) {
+    if (size != datasize()) {
+      SERIAL_ERROR_START();
+      SERIAL_ERRORLNPGM("EEPROM datasize error.");
+      return true;
+    }
+    return false;
+  }
+
   /**
    * M500 - Store Configuration
    */
@@ -348,6 +401,8 @@ void MarlinSettings::postprocess() {
 
     working_crc = 0; // clear before first "real data"
 
+    _FIELD_TEST(esteppers);
+
     const uint8_t esteppers = COUNT(planner.axis_steps_per_mm) - XYZ;
     EEPROM_WRITE(esteppers);
 
@@ -362,6 +417,9 @@ void MarlinSettings::postprocess() {
     EEPROM_WRITE(planner.min_travel_feedrate_mm_s);
     EEPROM_WRITE(planner.min_segment_time_us);
     EEPROM_WRITE(planner.max_jerk);
+
+    _FIELD_TEST(home_offset);
+
     #if !HAS_HOME_OFFSET
       const float home_offset[XYZ] = { 0 };
     #endif
@@ -411,6 +469,8 @@ void MarlinSettings::postprocess() {
       for (uint8_t q = mesh_num_x * mesh_num_y; q--;) EEPROM_WRITE(dummy);
     #endif // MESH_BED_LEVELING
 
+    _FIELD_TEST(zprobe_zoffset);
+
     #if !HAS_BED_PROBE
       const float zprobe_zoffset = 0;
     #endif
@@ -455,6 +515,8 @@ void MarlinSettings::postprocess() {
       for (uint16_t q = grid_max_x * grid_max_y; q--;) EEPROM_WRITE(dummy);
     #endif // AUTO_BED_LEVELING_BILINEAR
 
+    _FIELD_TEST(planner_leveling_active);
+
     #if ENABLED(AUTO_BED_LEVELING_UBL)
       EEPROM_WRITE(planner.leveling_active);
       EEPROM_WRITE(ubl.storage_slot);
@@ -467,6 +529,7 @@ void MarlinSettings::postprocess() {
 
     // 11 floats for DELTA / [XYZ]_DUAL_ENDSTOPS
     #if ENABLED(DELTA)
+      _FIELD_TEST(delta_height);
       EEPROM_WRITE(delta_height);              // 1 float
       EEPROM_WRITE(delta_endstop_adj);         // 3 floats
       EEPROM_WRITE(delta_radius);              // 1 float
@@ -476,6 +539,7 @@ void MarlinSettings::postprocess() {
       EEPROM_WRITE(delta_tower_angle_trim);    // 3 floats
 
     #elif ENABLED(X_DUAL_ENDSTOPS) || ENABLED(Y_DUAL_ENDSTOPS) || ENABLED(Z_DUAL_ENDSTOPS)
+      _FIELD_TEST(x_endstop_adj);
       // Write dual endstops in X, Y, Z order. Unused = 0.0
       dummy = 0.0f;
       #if ENABLED(X_DUAL_ENDSTOPS)
@@ -503,6 +567,8 @@ void MarlinSettings::postprocess() {
       for (uint8_t q = 11; q--;) EEPROM_WRITE(dummy);
     #endif
 
+    _FIELD_TEST(lcd_preheat_hotend_temp);
+
     #if DISABLED(ULTIPANEL)
       constexpr int lcd_preheat_hotend_temp[2] = { PREHEAT_1_TEMP_HOTEND, PREHEAT_2_TEMP_HOTEND },
                     lcd_preheat_bed_temp[2] = { PREHEAT_1_TEMP_BED, PREHEAT_2_TEMP_BED },
@@ -552,6 +618,8 @@ void MarlinSettings::postprocess() {
       EEPROM_WRITE(thermalManager.bedKd);
     #endif
 
+    _FIELD_TEST(lcd_contrast);
+
     #if !HAS_LCD_CONTRAST
       const uint16_t lcd_contrast = 32;
     #endif
@@ -577,6 +645,7 @@ void MarlinSettings::postprocess() {
     //
     // Volumetric & Filament Size
     //
+    _FIELD_TEST(parser_volumetric_enabled);
     #if DISABLED(NO_VOLUMETRICS)
 
       EEPROM_WRITE(parser.volumetric_enabled);
@@ -587,81 +656,81 @@ void MarlinSettings::postprocess() {
         EEPROM_WRITE(dummy);
       }
 
+    #else
+
+      const bool volumetric_enabled = false;
+      dummy = DEFAULT_NOMINAL_FILAMENT_DIA;
+      EEPROM_WRITE(volumetric_enabled);
+      for (uint8_t q = MAX_EXTRUDERS; q--;) EEPROM_WRITE(dummy);
+
     #endif
 
+    //
     // Save TMC2130 or TMC2208 Configuration, and placeholder values
-    uint16_t val;
-    #if HAS_TRINAMIC
-      #if X_IS_TRINAMIC
-        val = stepperX.getCurrent();
+    //
+    _FIELD_TEST(tmc_stepper_current);
+    uint16_t currents[11] = {
+      #if HAS_TRINAMIC
+        #if X_IS_TRINAMIC
+          stepperX.getCurrent(),
+        #else
+          0,
+        #endif
+        #if Y_IS_TRINAMIC
+          stepperY.getCurrent(),
+        #else
+          0,
+        #endif
+        #if Z_IS_TRINAMIC
+          stepperZ.getCurrent(),
+        #else
+          0,
+        #endif
+        #if X2_IS_TRINAMIC
+          stepperX2.getCurrent(),
+        #else
+          0,
+        #endif
+        #if Y2_IS_TRINAMIC
+          stepperY2.getCurrent(),
+        #else
+          0,
+        #endif
+        #if Z2_IS_TRINAMIC
+          stepperZ2.getCurrent(),
+        #else
+          0,
+        #endif
+        #if E0_IS_TRINAMIC
+          stepperE0.getCurrent(),
+        #else
+          0,
+        #endif
+        #if E1_IS_TRINAMIC
+          stepperE1.getCurrent(),
+        #else
+          0,
+        #endif
+        #if E2_IS_TRINAMIC
+          stepperE2.getCurrent(),
+        #else
+          0,
+        #endif
+        #if E3_IS_TRINAMIC
+          stepperE3.getCurrent(),
+        #else
+          0,
+        #endif
+        #if E4_IS_TRINAMIC
+          stepperE4.getCurrent()
+        #else
+          0
+        #endif
       #else
-        val = 0;
+        0
       #endif
-      EEPROM_WRITE(val);
-      #if Y_IS_TRINAMIC
-        val = stepperY.getCurrent();
-      #else
-        val = 0;
-      #endif
-      EEPROM_WRITE(val);
-      #if Z_IS_TRINAMIC
-        val = stepperZ.getCurrent();
-      #else
-        val = 0;
-      #endif
-      EEPROM_WRITE(val);
-      #if X2_IS_TRINAMIC
-        val = stepperX2.getCurrent();
-      #else
-        val = 0;
-      #endif
-      EEPROM_WRITE(val);
-      #if Y2_IS_TRINAMIC
-        val = stepperY2.getCurrent();
-      #else
-        val = 0;
-      #endif
-      EEPROM_WRITE(val);
-      #if Z2_IS_TRINAMIC
-        val = stepperZ2.getCurrent();
-      #else
-        val = 0;
-      #endif
-      EEPROM_WRITE(val);
-      #if E0_IS_TRINAMIC
-        val = stepperE0.getCurrent();
-      #else
-        val = 0;
-      #endif
-      EEPROM_WRITE(val);
-      #if E1_IS_TRINAMIC
-        val = stepperE1.getCurrent();
-      #else
-        val = 0;
-      #endif
-      EEPROM_WRITE(val);
-      #if E2_IS_TRINAMIC
-        val = stepperE2.getCurrent();
-      #else
-        val = 0;
-      #endif
-      EEPROM_WRITE(val);
-      #if E3_IS_TRINAMIC
-        val = stepperE3.getCurrent();
-      #else
-        val = 0;
-      #endif
-      EEPROM_WRITE(val);
-      #if E4_IS_TRINAMIC
-        val = stepperE4.getCurrent();
-      #else
-        val = 0;
-      #endif
-      EEPROM_WRITE(val);
-    #else
-      val = 0;
-      for (uint8_t q = 11; q--;) EEPROM_WRITE(val);
-    #endif
+    };
+    EEPROM_WRITE(currents);
 
     //
     // TMC2130 Sensorless homing threshold
@@ -688,7 +757,7 @@ void MarlinSettings::postprocess() {
     //
     // Linear Advance
     //
-
+    _FIELD_TEST(planner_extruder_advance_k);
     #if ENABLED(LIN_ADVANCE)
       EEPROM_WRITE(planner.extruder_advance_k);
       EEPROM_WRITE(planner.advance_ed_ratio);
@@ -708,18 +777,18 @@ void MarlinSettings::postprocess() {
     //
     // CNC Coordinate Systems
     //
-
+    _FIELD_TEST(coordinate_system);
     #if ENABLED(CNC_COORDINATE_SYSTEMS)
       EEPROM_WRITE(coordinate_system); // 27 floats
     #else
       dummy = 0.0f;
-      for (uint8_t q = 27; q--;) EEPROM_WRITE(dummy);
+      for (uint8_t q = MAX_COORDINATE_SYSTEMS * XYZ; q--;) EEPROM_WRITE(dummy);
     #endif
 
     //
     // Skew correction factors
     //
-
+    _FIELD_TEST(planner_xy_skew_factor);
     #if ENABLED(SKEW_CORRECTION)
       EEPROM_WRITE(planner.xy_skew_factor);
       EEPROM_WRITE(planner.xz_skew_factor);
@@ -732,6 +801,7 @@ void MarlinSettings::postprocess() {
     //
     // Advanced Pause filament load & unload lengths
     //
+    _FIELD_TEST(filament_change_unload_length);
     #if ENABLED(ADVANCED_PAUSE_FEATURE)
       for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
         if (q < COUNT(filament_change_unload_length)) dummy = filament_change_unload_length[q];
@@ -746,10 +816,12 @@ void MarlinSettings::postprocess() {
       for (uint8_t q = MAX_EXTRUDERS * 2; q--;) EEPROM_WRITE(dummy);
     #endif
 
+    //
+    // Validate CRC and Data Size
+    //
     if (!eeprom_error) {
-      const int eeprom_size = eeprom_index;
-
-      const uint16_t final_crc = working_crc;
+      const uint16_t eeprom_size = eeprom_index - (EEPROM_OFFSET),
+                     final_crc = working_crc;
 
       // Write the EEPROM header
       eeprom_index = EEPROM_OFFSET;
@@ -760,12 +832,17 @@ void MarlinSettings::postprocess() {
       // Report storage size
       #if ENABLED(EEPROM_CHITCHAT)
         SERIAL_ECHO_START();
-        SERIAL_ECHOPAIR("Settings Stored (", eeprom_size - (EEPROM_OFFSET));
+        SERIAL_ECHOPAIR("Settings Stored (", eeprom_size);
         SERIAL_ECHOPAIR(" bytes; crc ", (uint32_t)final_crc);
         SERIAL_ECHOLNPGM(")");
       #endif
+
+      eeprom_error |= size_error(eeprom_size);
     }
 
+    //
+    // UBL Mesh
+    //
     #if ENABLED(UBL_SAVE_ACTIVE_ON_M500)
       if (ubl.storage_slot >= 0)
         store_mesh(ubl.storage_slot);
@@ -777,16 +854,16 @@ void MarlinSettings::postprocess() {
   /**
    * M501 - Retrieve Configuration
    */
-  bool MarlinSettings::load() {
+  bool MarlinSettings::_load() {
     uint16_t working_crc = 0;
 
     EEPROM_START();
 
     char stored_ver[4];
-    EEPROM_READ(stored_ver);
+    EEPROM_READ_ALWAYS(stored_ver);
 
     uint16_t stored_crc;
-    EEPROM_READ(stored_crc);
+    EEPROM_READ_ALWAYS(stored_crc);
 
     // Version has to match or defaults are used
     if (strncmp(version, stored_ver, 3) != 0) {
@@ -800,7 +877,8 @@ void MarlinSettings::postprocess() {
         SERIAL_ECHOPAIR("(EEPROM=", stored_ver);
         SERIAL_ECHOLNPGM(" Marlin=" EEPROM_VERSION ")");
       #endif
-      reset();
+      if (!validating) reset();
+      eeprom_error = true;
     }
     else {
       float dummy = 0;
@@ -812,7 +890,7 @@ void MarlinSettings::postprocess() {
 
       // Number of esteppers may change
       uint8_t esteppers;
-      EEPROM_READ(esteppers);
+      EEPROM_READ_ALWAYS(esteppers);
 
       //
       // Planner Motion
@@ -827,7 +905,7 @@ void MarlinSettings::postprocess() {
       EEPROM_READ(tmp1);
       EEPROM_READ(tmp2);
       EEPROM_READ(tmp3);
-      LOOP_XYZE_N(i) {
+      if (!validating) LOOP_XYZE_N(i) {
         planner.axis_steps_per_mm[i]          = i < XYZ + esteppers ? tmp1[i] : def1[i < COUNT(def1) ? i : COUNT(def1) - 1];
         planner.max_feedrate_mm_s[i]          = i < XYZ + esteppers ? tmp2[i] : def2[i < COUNT(def2) ? i : COUNT(def2) - 1];
         planner.max_acceleration_mm_per_s2[i] = i < XYZ + esteppers ? tmp3[i] : def3[i < COUNT(def3) ? i : COUNT(def3) - 1];
@@ -876,21 +954,23 @@ void MarlinSettings::postprocess() {
 
       bool leveling_is_on;
       uint8_t mesh_num_x, mesh_num_y;
-      EEPROM_READ(leveling_is_on);
+      EEPROM_READ_ALWAYS(leveling_is_on);
       EEPROM_READ(dummy);
-      EEPROM_READ(mesh_num_x);
-      EEPROM_READ(mesh_num_y);
+      EEPROM_READ_ALWAYS(mesh_num_x);
+      EEPROM_READ_ALWAYS(mesh_num_y);
 
       #if ENABLED(MESH_BED_LEVELING)
-        mbl.has_mesh = leveling_is_on;
-        mbl.z_offset = dummy;
+        if (!validating) {
+          mbl.has_mesh = leveling_is_on;
+          mbl.z_offset = dummy;
+        }
         if (mesh_num_x == GRID_MAX_POINTS_X && mesh_num_y == GRID_MAX_POINTS_Y) {
           // EEPROM data fits the current mesh
           EEPROM_READ(mbl.z_values);
         }
         else {
           // EEPROM data is stale
-          mbl.reset();
+          if (!validating) mbl.reset();
           for (uint16_t q = mesh_num_x * mesh_num_y; q--;) EEPROM_READ(dummy);
         }
       #else
@@ -918,11 +998,11 @@ void MarlinSettings::postprocess() {
       //
 
       uint8_t grid_max_x, grid_max_y;
-      EEPROM_READ(grid_max_x);                       // 1 byte
-      EEPROM_READ(grid_max_y);                       // 1 byte
+      EEPROM_READ_ALWAYS(grid_max_x);                       // 1 byte
+      EEPROM_READ_ALWAYS(grid_max_y);                       // 1 byte
       #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
         if (grid_max_x == GRID_MAX_POINTS_X && grid_max_y == GRID_MAX_POINTS_Y) {
-          set_bed_leveling_enabled(false);
+          if (!validating) set_bed_leveling_enabled(false);
           EEPROM_READ(bilinear_grid_spacing);        // 2 ints
           EEPROM_READ(bilinear_start);               // 2 ints
           EEPROM_READ(z_values);                     // 9 to 256 floats
@@ -1014,7 +1094,7 @@ void MarlinSettings::postprocess() {
           EEPROM_READ(dummy); // Kp
           if (e < HOTENDS && dummy != DUMMY_PID_VALUE) {
             // do not need to scale PID values as the values in EEPROM are already scaled
-            PID_PARAM(Kp, e) = dummy;
+            if (!validating) PID_PARAM(Kp, e) = dummy;
             EEPROM_READ(PID_PARAM(Ki, e));
             EEPROM_READ(PID_PARAM(Kd, e));
             #if ENABLED(PID_EXTRUSION_SCALING)
@@ -1048,7 +1128,7 @@ void MarlinSettings::postprocess() {
       #if ENABLED(PIDTEMPBED)
         EEPROM_READ(dummy); // bedKp
         if (dummy != DUMMY_PID_VALUE) {
-          thermalManager.bedKp = dummy;
+          if (!validating) thermalManager.bedKp = dummy;
           EEPROM_READ(thermalManager.bedKi);
           EEPROM_READ(thermalManager.bedKd);
         }
@@ -1093,63 +1173,62 @@ void MarlinSettings::postprocess() {
 
         for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
           EEPROM_READ(dummy);
-          if (q < COUNT(planner.filament_size)) planner.filament_size[q] = dummy;
+          if (!validating && q < COUNT(planner.filament_size))
+            planner.filament_size[q] = dummy;
         }
 
+      #else
+
+        EEPROM_READ(dummyb);
+        for (uint8_t q=MAX_EXTRUDERS; q--;) EEPROM_READ(dummy);
+
       #endif
 
       //
       // TMC2130 Stepper Current
       //
-
-      uint16_t val;
       #if HAS_TRINAMIC
+        #define SET_CURR(N,Q) stepper##Q.setCurrent(val[N], R_SENSE, HOLD_MULTIPLIER)
+        uint16_t val[11];
         EEPROM_READ(val);
-        #if X_IS_TRINAMIC
-          stepperX.setCurrent(val, R_SENSE, HOLD_MULTIPLIER);
-        #endif
-        EEPROM_READ(val);
-        #if Y_IS_TRINAMIC
-          stepperY.setCurrent(val, R_SENSE, HOLD_MULTIPLIER);
-        #endif
-        EEPROM_READ(val);
-        #if Z_IS_TRINAMIC
-          stepperZ.setCurrent(val, R_SENSE, HOLD_MULTIPLIER);
-        #endif
-        EEPROM_READ(val);
-        #if X2_IS_TRINAMIC
-          stepperX2.setCurrent(val, R_SENSE, HOLD_MULTIPLIER);
-        #endif
-        EEPROM_READ(val);
-        #if Y2_IS_TRINAMIC
-          stepperY2.setCurrent(val, R_SENSE, HOLD_MULTIPLIER);
-        #endif
-        EEPROM_READ(val);
-        #if Z2_IS_TRINAMIC
-          stepperZ2.setCurrent(val, R_SENSE, HOLD_MULTIPLIER);
-        #endif
-        EEPROM_READ(val);
-        #if E0_IS_TRINAMIC
-          stepperE0.setCurrent(val, R_SENSE, HOLD_MULTIPLIER);
-        #endif
-        EEPROM_READ(val);
-        #if E1_IS_TRINAMIC
-          stepperE1.setCurrent(val, R_SENSE, HOLD_MULTIPLIER);
-        #endif
-        EEPROM_READ(val);
-        #if E2_IS_TRINAMIC
-          stepperE2.setCurrent(val, R_SENSE, HOLD_MULTIPLIER);
-        #endif
-        EEPROM_READ(val);
-        #if E3_IS_TRINAMIC
-          stepperE3.setCurrent(val, R_SENSE, HOLD_MULTIPLIER);
-        #endif
-        EEPROM_READ(val);
-        #if E4_IS_TRINAMIC
-          stepperE4.setCurrent(val, R_SENSE, HOLD_MULTIPLIER);
-        #endif
+        if (!validating) {
+          #if X_IS_TRINAMIC
+            SET_CURR(0, X);
+          #endif
+          #if Y_IS_TRINAMIC
+            SET_CURR(1, Y);
+          #endif
+          #if Z_IS_TRINAMIC
+            SET_CURR(2, Z);
+          #endif
+          #if X2_IS_TRINAMIC
+            SET_CURR(3, X2);
+          #endif
+          #if Y2_IS_TRINAMIC
+            SET_CURR(4, Y2);
+          #endif
+          #if Z2_IS_TRINAMIC
+            SET_CURR(5, Z2);
+          #endif
+          #if E0_IS_TRINAMIC
+            SET_CURR(6, E0);
+          #endif
+          #if E1_IS_TRINAMIC
+            SET_CURR(7, E1);
+          #endif
+          #if E2_IS_TRINAMIC
+            SET_CURR(8, E2);
+          #endif
+          #if E3_IS_TRINAMIC
+            SET_CURR(9, E3);
+          #endif
+          #if E4_IS_TRINAMIC
+            SET_CURR(10, E4);
+          #endif
+        }
       #else
-        for (uint8_t q = 11; q--;) EEPROM_READ(val);
+        uint16_t val;
+        for (uint8_t q=11; q--;) EEPROM_READ(val);
       #endif
 
       /*
@@ -1160,19 +1239,23 @@ void MarlinSettings::postprocess() {
       int16_t thrs;
       #if ENABLED(SENSORLESS_HOMING)
         EEPROM_READ(thrs);
-        #if ENABLED(X_IS_TMC2130)
-          stepperX.sgt(thrs);
-        #endif
-        #if ENABLED(X2_IS_TMC2130)
-          stepperX2.sgt(thrs);
-        #endif
+        if (!validating) {
+          #if ENABLED(X_IS_TMC2130)
+            stepperX.sgt(thrs);
+          #endif
+          #if ENABLED(X2_IS_TMC2130)
+            stepperX2.sgt(thrs);
+          #endif
+        }
         EEPROM_READ(thrs);
-        #if ENABLED(Y_IS_TMC2130)
-          stepperY.sgt(thrs);
-        #endif
-        #if ENABLED(Y2_IS_TMC2130)
-          stepperY2.sgt(thrs);
-        #endif
+        if (!validating) {
+          #if ENABLED(Y_IS_TMC2130)
+            stepperY.sgt(thrs);
+          #endif
+          #if ENABLED(Y2_IS_TMC2130)
+            stepperY2.sgt(thrs);
+          #endif
+        }
       #else
         for (uint8_t q = 0; q < 2; q++) EEPROM_READ(thrs);
       #endif
@@ -1205,10 +1288,10 @@ void MarlinSettings::postprocess() {
       //
 
       #if ENABLED(CNC_COORDINATE_SYSTEMS)
-        (void)select_coordinate_system(-1); // Go back to machine space
+        if (!validating) (void)select_coordinate_system(-1); // Go back to machine space
         EEPROM_READ(coordinate_system);                  // 27 floats
       #else
-        for (uint8_t q = 27; q--;) EEPROM_READ(dummy);
+        for (uint8_t q = MAX_COORDINATE_SYSTEMS * XYZ; q--;) EEPROM_READ(dummy);
       #endif
 
       //
@@ -1235,27 +1318,24 @@ void MarlinSettings::postprocess() {
       #if ENABLED(ADVANCED_PAUSE_FEATURE)
         for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
           EEPROM_READ(dummy);
-          if (q < COUNT(filament_change_unload_length)) filament_change_unload_length[q] = dummy;
+          if (!validating && q < COUNT(filament_change_unload_length)) filament_change_unload_length[q] = dummy;
         }
         for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
           EEPROM_READ(dummy);
-          if (q < COUNT(filament_change_load_length)) filament_change_load_length[q] = dummy;
+          if (!validating && q < COUNT(filament_change_load_length)) filament_change_load_length[q] = dummy;
         }
       #else
         for (uint8_t q = MAX_EXTRUDERS * 2; q--;) EEPROM_READ(dummy);
       #endif
 
-      if (working_crc == stored_crc) {
-        postprocess();
-        #if ENABLED(EEPROM_CHITCHAT)
-          SERIAL_ECHO_START();
-          SERIAL_ECHO(version);
-          SERIAL_ECHOPAIR(" stored settings retrieved (", eeprom_index - (EEPROM_OFFSET));
-          SERIAL_ECHOPAIR(" bytes; crc ", (uint32_t)working_crc);
-          SERIAL_ECHOLNPGM(")");
-        #endif
+      eeprom_error = size_error(eeprom_index - (EEPROM_OFFSET));
+      if (eeprom_error) {
+        SERIAL_ECHO_START();
+        SERIAL_ECHOPAIR("Index: ", int(eeprom_index - (EEPROM_OFFSET)));
+        SERIAL_ECHOLNPAIR(" Size: ", datasize());
       }
-      else {
+      else if (working_crc != stored_crc) {
+        eeprom_error = true;
         #if ENABLED(EEPROM_CHITCHAT)
           SERIAL_ERROR_START();
           SERIAL_ERRORPGM("EEPROM CRC mismatch - (stored) ");
@@ -1264,54 +1344,79 @@ void MarlinSettings::postprocess() {
           SERIAL_ERROR(working_crc);
           SERIAL_ERRORLNPGM(" (calculated)!");
         #endif
-        reset();
+      }
+      else if (!validating) {
+        #if ENABLED(EEPROM_CHITCHAT)
+          SERIAL_ECHO_START();
+          SERIAL_ECHO(version);
+          SERIAL_ECHOPAIR(" stored settings retrieved (", eeprom_index - (EEPROM_OFFSET));
+          SERIAL_ECHOPAIR(" bytes; crc ", (uint32_t)working_crc);
+          SERIAL_ECHOLNPGM(")");
+        #endif
+      }
+
+      if (!validating) {
+        if (eeprom_error) reset(); else postprocess();
       }
 
       #if ENABLED(AUTO_BED_LEVELING_UBL)
-        meshes_begin = (eeprom_index + 32) & 0xFFF8;  // Pad the end of configuration data so it
-                                                      // can float up or down a little bit without
-                                                      // disrupting the mesh data
         ubl.report_state();
 
-        if (!ubl.sanity_check()) {
-          SERIAL_EOL();
-          #if ENABLED(EEPROM_CHITCHAT)
-            ubl.echo_name();
-            SERIAL_ECHOLNPGM(" initialized.\n");
-          #endif
-        }
-        else {
-          #if ENABLED(EEPROM_CHITCHAT)
-            SERIAL_PROTOCOLPGM("?Can't enable ");
-            ubl.echo_name();
-            SERIAL_PROTOCOLLNPGM(".");
-          #endif
-          ubl.reset();
-        }
+        if (!validating) {
+          if (!ubl.sanity_check()) {
+            SERIAL_EOL();
+            #if ENABLED(EEPROM_CHITCHAT)
+              ubl.echo_name();
+              SERIAL_ECHOLNPGM(" initialized.\n");
+            #endif
+          }
+          else {
+            eeprom_error = true;
+            #if ENABLED(EEPROM_CHITCHAT)
+              SERIAL_PROTOCOLPGM("?Can't enable ");
+              ubl.echo_name();
+              SERIAL_PROTOCOLLNPGM(".");
+            #endif
+            ubl.reset();
+          }
 
-        if (ubl.storage_slot >= 0) {
-          load_mesh(ubl.storage_slot);
-          #if ENABLED(EEPROM_CHITCHAT)
-            SERIAL_ECHOPAIR("Mesh ", ubl.storage_slot);
-            SERIAL_ECHOLNPGM(" loaded from storage.");
-          #endif
-        }
-        else {
-          ubl.reset();
-          #if ENABLED(EEPROM_CHITCHAT)
-            SERIAL_ECHOLNPGM("UBL System reset()");
-          #endif
+          if (ubl.storage_slot >= 0) {
+            load_mesh(ubl.storage_slot);
+            #if ENABLED(EEPROM_CHITCHAT)
+              SERIAL_ECHOPAIR("Mesh ", ubl.storage_slot);
+              SERIAL_ECHOLNPGM(" loaded from storage.");
+            #endif
+          }
+          else {
+            ubl.reset();
+            #if ENABLED(EEPROM_CHITCHAT)
+              SERIAL_ECHOLNPGM("UBL System reset()");
+            #endif
+          }
         }
       #endif
     }
 
     #if ENABLED(EEPROM_CHITCHAT) && DISABLED(DISABLE_M503)
-      report();
+      if (!validating) report();
     #endif
 
     return !eeprom_error;
   }
 
+  bool MarlinSettings::validate() {
+    validating = true;
+    const bool success = _load();
+    validating = false;
+    return success;
+  }
+
+  bool MarlinSettings::load() {
+    if (validate()) return _load();
+    reset();
+    return true;
+  }
+
   #if ENABLED(AUTO_BED_LEVELING_UBL)
 
     #if ENABLED(EEPROM_CHITCHAT)
@@ -1322,12 +1427,13 @@ void MarlinSettings::postprocess() {
       }
     #endif
 
+    int16_t MarlinSettings::meshes_start_index() {
+      return (datasize() + EEPROM_OFFSET + 32) & 0xFFF8;  // Pad the end of configuration data so it can float up
+                                                          // or down a little bit without disrupting the mesh data
+    }
+
     uint16_t MarlinSettings::calc_num_meshes() {
-      //obviously this will get more sophisticated once we've added an actual MAT
-
-      if (meshes_begin <= 0) return 0;
-
-      return (meshes_end - meshes_begin) / sizeof(ubl.z_values);
+      return (meshes_end - meshes_start_index()) / sizeof(ubl.z_values);
     }
 
     void MarlinSettings::store_mesh(const int8_t slot) {
diff --git a/Marlin/configuration_store.h b/Marlin/configuration_store.h
index aa25115eb28..54102807b79 100644
--- a/Marlin/configuration_store.h
+++ b/Marlin/configuration_store.h
@@ -29,31 +29,31 @@ class MarlinSettings {
   public:
     MarlinSettings() { }
 
+    static uint16_t datasize();
+
     static void reset();
-    static bool save();
+    static bool save();   // Return 'true' if data was saved
 
     FORCE_INLINE static bool init_eeprom() {
       bool success = true;
       reset();
       #if ENABLED(EEPROM_SETTINGS)
-        if ((success = save())) {
-          #if ENABLED(AUTO_BED_LEVELING_UBL)
-            success = load(); // UBL uses load() to know the end of EEPROM
-          #elif ENABLED(EEPROM_CHITCHAT)
-            report();
-          #endif
-        }
+        success = save();
+        #if ENABLED(EEPROM_CHITCHAT)
+          if (success) report();
+        #endif
       #endif
       return success;
     }
 
     #if ENABLED(EEPROM_SETTINGS)
-      static bool load();
+      static bool load();     // Return 'true' if data was loaded ok
+      static bool validate(); // Return 'true' if EEPROM data is ok
 
       #if ENABLED(AUTO_BED_LEVELING_UBL) // Eventually make these available if any leveling system
                                          // That can store is enabled
-        FORCE_INLINE static int16_t get_start_of_meshes() { return meshes_begin; }
-        FORCE_INLINE static int16_t get_end_of_meshes() { return meshes_end; }
+        static int16_t meshes_start_index();
+        FORCE_INLINE static int16_t meshes_end_index() { return meshes_end; }
         static uint16_t calc_num_meshes();
         static void store_mesh(const int8_t slot);
         static void load_mesh(const int8_t slot, void * const into=NULL);
@@ -77,7 +77,8 @@ class MarlinSettings {
     static void postprocess();
 
     #if ENABLED(EEPROM_SETTINGS)
-      static bool eeprom_error;
+
+      static bool eeprom_error, validating;
 
       #if ENABLED(AUTO_BED_LEVELING_UBL) // Eventually make these available if any leveling system
                                          // That can store is enabled
@@ -87,8 +88,10 @@ class MarlinSettings {
 
       #endif
 
+      static bool _load();
       static void write_data(int &pos, const uint8_t *value, uint16_t size, uint16_t *crc);
-      static void read_data(int &pos, uint8_t *value, uint16_t size, uint16_t *crc);
+      static void read_data(int &pos, uint8_t *value, uint16_t size, uint16_t *crc, const bool force=false);
+      static bool size_error(const uint16_t size);
     #endif
 };
 
diff --git a/Marlin/ubl_G29.cpp b/Marlin/ubl_G29.cpp
index e741e391d66..e1b00b47519 100644
--- a/Marlin/ubl_G29.cpp
+++ b/Marlin/ubl_G29.cpp
@@ -308,12 +308,6 @@
 
   void unified_bed_leveling::G29() {
 
-    if (!settings.calc_num_meshes()) {
-      SERIAL_PROTOCOLLNPGM("?Enable EEPROM and init with");
-      SERIAL_PROTOCOLLNPGM("M502, M500, M501 in that order.\n");
-      return;
-    }
-
     if (g29_parameter_parsing()) return; // abort if parsing the simple parameters causes a problem,
 
     // Check for commands that require the printer to be homed
@@ -1273,8 +1267,8 @@
       SERIAL_EOL();
       safe_delay(50);
 
-      SERIAL_PROTOCOLPAIR("Meshes go from ", hex_address((void*)settings.get_start_of_meshes()));
-      SERIAL_PROTOCOLLNPAIR(" to ", hex_address((void*)settings.get_end_of_meshes()));
+      SERIAL_PROTOCOLPAIR("Meshes go from ", hex_address((void*)settings.meshes_start_index()));
+      SERIAL_PROTOCOLLNPAIR(" to ", hex_address((void*)settings.meshes_end_index()));
       safe_delay(50);
 
       SERIAL_PROTOCOLLNPAIR("sizeof(ubl) :  ", (int)sizeof(ubl));
@@ -1283,7 +1277,7 @@
       SERIAL_EOL();
       safe_delay(25);
 
-      SERIAL_PROTOCOLLNPAIR("EEPROM free for UBL: ", hex_address((void*)(settings.get_end_of_meshes() - settings.get_start_of_meshes())));
+      SERIAL_PROTOCOLLNPAIR("EEPROM free for UBL: ", hex_address((void*)(settings.meshes_end_index() - settings.meshes_start_index())));
       safe_delay(50);
 
       SERIAL_PROTOCOLPAIR("EEPROM can hold ", settings.calc_num_meshes());
diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp
index 7d14983ac09..a66003d3113 100644
--- a/Marlin/ultralcd.cpp
+++ b/Marlin/ultralcd.cpp
@@ -2303,7 +2303,6 @@ void kill_screen(const char* lcd_msg) {
       MENU_BACK(MSG_UBL_LEVEL_BED);
       if (!WITHIN(ubl_storage_slot, 0, a - 1)) {
         STATIC_ITEM(MSG_NO_STORAGE);
-        STATIC_ITEM(MSG_INIT_EEPROM);
       }
       else {
         MENU_ITEM_EDIT(int3, MSG_UBL_STORAGE_SLOT, &ubl_storage_slot, 0, a - 1);
@@ -4538,6 +4537,24 @@ void kill_screen(const char* lcd_msg) {
       END_SCREEN();
     }
 
+    FORCE_INLINE screenFunc_t ap_message_screen(const AdvancedPauseMessage message) {
+      switch (message) {
+        case ADVANCED_PAUSE_MESSAGE_INIT: return lcd_advanced_pause_init_message;
+        case ADVANCED_PAUSE_MESSAGE_UNLOAD: return lcd_advanced_pause_unload_message;
+        case ADVANCED_PAUSE_MESSAGE_INSERT: return lcd_advanced_pause_insert_message;
+        case ADVANCED_PAUSE_MESSAGE_LOAD: return lcd_advanced_pause_load_message;
+        case ADVANCED_PAUSE_MESSAGE_PURGE: return lcd_advanced_pause_purge_message;
+        case ADVANCED_PAUSE_MESSAGE_RESUME: return lcd_advanced_pause_resume_message;
+        case ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE: return lcd_advanced_pause_heat_nozzle;
+        case ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT: return lcd_advanced_pause_wait_for_nozzles_to_heat;
+        case ADVANCED_PAUSE_MESSAGE_OPTION: advanced_pause_menu_response = ADVANCED_PAUSE_RESPONSE_WAIT_FOR;
+                                            return lcd_advanced_pause_option_menu;
+        case ADVANCED_PAUSE_MESSAGE_STATUS:
+        default: break;
+      }
+      return NULL;
+    }
+
     void lcd_advanced_pause_show_message(
       const AdvancedPauseMessage message,
       const AdvancedPauseMode mode/*=ADVANCED_PAUSE_MODE_PAUSE_PRINT*/,
@@ -4545,48 +4562,13 @@ void kill_screen(const char* lcd_msg) {
     ) {
       advanced_pause_mode = mode;
       hotend_status_extruder = extruder;
-      switch (message) {
-        case ADVANCED_PAUSE_MESSAGE_INIT:
-          defer_return_to_status = true;
-          lcd_goto_screen(lcd_advanced_pause_init_message);
-          break;
-        case ADVANCED_PAUSE_MESSAGE_UNLOAD:
-          defer_return_to_status = true;
-          lcd_goto_screen(lcd_advanced_pause_unload_message);
-          break;
-        case ADVANCED_PAUSE_MESSAGE_INSERT:
-          defer_return_to_status = true;
-          lcd_goto_screen(lcd_advanced_pause_insert_message);
-          break;
-        case ADVANCED_PAUSE_MESSAGE_LOAD:
-          defer_return_to_status = true;
-          lcd_goto_screen(lcd_advanced_pause_load_message);
-          break;
-        case ADVANCED_PAUSE_MESSAGE_PURGE:
-          defer_return_to_status = true;
-          lcd_goto_screen(lcd_advanced_pause_purge_message);
-          break;
-        case ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE:
-          defer_return_to_status = true;
-          lcd_goto_screen(lcd_advanced_pause_heat_nozzle);
-          break;
-        case ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT:
-          defer_return_to_status = true;
-          lcd_goto_screen(lcd_advanced_pause_wait_for_nozzles_to_heat);
-          break;
-        case ADVANCED_PAUSE_MESSAGE_OPTION:
-          defer_return_to_status = true;
-          advanced_pause_menu_response = ADVANCED_PAUSE_RESPONSE_WAIT_FOR;
-          lcd_goto_screen(lcd_advanced_pause_option_menu);
-          break;
-        case ADVANCED_PAUSE_MESSAGE_RESUME:
-          defer_return_to_status = true;
-          lcd_goto_screen(lcd_advanced_pause_resume_message);
-          break;
-        case ADVANCED_PAUSE_MESSAGE_STATUS:
-          lcd_return_to_status();
-          break;
+      const screenFunc_t next_screen = ap_message_screen(message);
+      if (next_screen) {
+        defer_return_to_status = true;
+        lcd_goto_screen(next_screen);
       }
+      else
+        lcd_return_to_status();
     }
 
   #endif // ADVANCED_PAUSE_FEATURE
diff --git a/Marlin/vector_3.cpp b/Marlin/vector_3.cpp
index f9615bcf08a..8c30830e67d 100644
--- a/Marlin/vector_3.cpp
+++ b/Marlin/vector_3.cpp
@@ -157,4 +157,3 @@ void matrix_3x3::debug(const char * const title) {
 }
 
 #endif // HAS_ABL
-
diff --git a/Marlin/vector_3.h b/Marlin/vector_3.h
index 19f6e3a3a7b..a92660018ff 100644
--- a/Marlin/vector_3.h
+++ b/Marlin/vector_3.h
@@ -41,8 +41,6 @@
 #ifndef VECTOR_3_H
 #define VECTOR_3_H
 
-#if HAS_ABL
-
 class matrix_3x3;
 
 struct vector_3 {
@@ -79,5 +77,4 @@ struct matrix_3x3 {
 
 void apply_rotation_xyz(matrix_3x3 rotationMatrix, float &x, float &y, float &z);
 
-#endif // HAS_ABL
 #endif // VECTOR_3_H