diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp
index 4603c76967..fafce9a896 100644
--- a/Marlin/src/gcode/calibrate/G28.cpp
+++ b/Marlin/src/gcode/calibrate/G28.cpp
@@ -255,28 +255,28 @@ void GcodeSuite::G28() {
   #define HAS_HOMING_CURRENT (HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(X2) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Y2))
 
   #if HAS_HOMING_CURRENT
-    auto debug_current = [](const char * const s, const int16_t a, const int16_t b){
-      DEBUG_ECHO(s); DEBUG_ECHOLNPAIR(" current: ", a, " -> ", b);
+    auto debug_current = [](PGM_P const s, const int16_t a, const int16_t b){
+      serialprintPGM(s); DEBUG_ECHOLNPAIR(" current: ", a, " -> ", b);
     };
     #if HAS_CURRENT_HOME(X)
       const int16_t tmc_save_current_X = stepperX.getMilliamps();
       stepperX.rms_current(X_CURRENT_HOME);
-      if (DEBUGGING(LEVELING)) debug_current("X", tmc_save_current_X, X_CURRENT_HOME);
+      if (DEBUGGING(LEVELING)) debug_current(PSTR("X"), tmc_save_current_X, X_CURRENT_HOME);
     #endif
     #if HAS_CURRENT_HOME(X2)
       const int16_t tmc_save_current_X2 = stepperX2.getMilliamps();
       stepperX2.rms_current(X2_CURRENT_HOME);
-      if (DEBUGGING(LEVELING)) debug_current("X2", tmc_save_current_X2, X2_CURRENT_HOME);
+      if (DEBUGGING(LEVELING)) debug_current(PSTR("X2"), tmc_save_current_X2, X2_CURRENT_HOME);
     #endif
     #if HAS_CURRENT_HOME(Y)
       const int16_t tmc_save_current_Y = stepperY.getMilliamps();
       stepperY.rms_current(Y_CURRENT_HOME);
-      if (DEBUGGING(LEVELING)) debug_current("Y", tmc_save_current_Y, Y_CURRENT_HOME);
+      if (DEBUGGING(LEVELING)) debug_current(PSTR("Y"), tmc_save_current_Y, Y_CURRENT_HOME);
     #endif
     #if HAS_CURRENT_HOME(Y2)
       const int16_t tmc_save_current_Y2 = stepperY2.getMilliamps();
       stepperY2.rms_current(Y2_CURRENT_HOME);
-      if (DEBUGGING(LEVELING)) debug_current("Y2", tmc_save_current_Y2, Y2_CURRENT_HOME);
+      if (DEBUGGING(LEVELING)) debug_current(PSTR("Y2"), tmc_save_current_Y2, Y2_CURRENT_HOME);
     #endif
   #endif
 
@@ -345,12 +345,8 @@ void GcodeSuite::G28() {
     #endif
 
     // Home Y (before X)
-    #if ENABLED(HOME_Y_BEFORE_X)
-
-      if (doY || (doX && ENABLED(CODEPENDENT_XY_HOMING)))
-        homeaxis(Y_AXIS);
-
-    #endif
+    if (ENABLED(HOME_Y_BEFORE_X) && (doY || (ENABLED(CODEPENDENT_XY_HOMING) && doX)))
+      homeaxis(Y_AXIS);
 
     // Home X
     if (doX || (doY && ENABLED(CODEPENDENT_XY_HOMING) && DISABLED(HOME_Y_BEFORE_X))) {
diff --git a/Marlin/src/gcode/calibrate/G425.cpp b/Marlin/src/gcode/calibrate/G425.cpp
index 69fb29165d..42c56fe51d 100644
--- a/Marlin/src/gcode/calibrate/G425.cpp
+++ b/Marlin/src/gcode/calibrate/G425.cpp
@@ -37,6 +37,21 @@
 #include "../../module/endstops.h"
 #include "../../feature/bedlevel/bedlevel.h"
 
+#if !AXIS_CAN_CALIBRATE(X)
+  #undef CALIBRATION_MEASURE_LEFT
+  #undef CALIBRATION_MEASURE_RIGHT
+#endif
+
+#if !AXIS_CAN_CALIBRATE(Y)
+  #undef CALIBRATION_MEASURE_FRONT
+  #undef CALIBRATION_MEASURE_BACK
+#endif
+
+#if !AXIS_CAN_CALIBRATE(Z)
+  #undef CALIBRATION_MEASURE_AT_TOP_EDGES
+#endif
+
+
 /**
  * G425 backs away from the calibration object by various distances
  * depending on the confidence level:
@@ -207,42 +222,52 @@ inline float measure(const AxisEnum axis, const int dir, const bool stop_state,
 inline void probe_side(measurements_t &m, const float uncertainty, const side_t side, const bool probe_top_at_edge=false) {
   const xyz_float_t dimensions = CALIBRATION_OBJECT_DIMENSIONS;
   AxisEnum axis;
-  float dir;
+  float dir = 1;
 
   park_above_object(m, uncertainty);
 
   switch (side) {
-    case TOP: {
-      const float measurement = measure(Z_AXIS, -1, true, &m.backlash[TOP], uncertainty);
-      m.obj_center.z = measurement - dimensions.z / 2;
-      m.obj_side[TOP] = measurement;
-      return;
-    }
-    case RIGHT: axis = X_AXIS; dir = -1; break;
-    case FRONT: axis = Y_AXIS; dir =  1; break;
-    case LEFT:  axis = X_AXIS; dir =  1; break;
-    case BACK:  axis = Y_AXIS; dir = -1; break;
+    #if AXIS_CAN_CALIBRATE(Z)
+      case TOP: {
+        const float measurement = measure(Z_AXIS, -1, true, &m.backlash[TOP], uncertainty);
+        m.obj_center.z = measurement - dimensions.z / 2;
+        m.obj_side[TOP] = measurement;
+        return;
+      }
+    #endif
+    #if AXIS_CAN_CALIBRATE(X)
+      case LEFT:  axis = X_AXIS; break;
+      case RIGHT: axis = X_AXIS; dir = -1; break;
+    #endif
+    #if AXIS_CAN_CALIBRATE(Y)
+      case FRONT: axis = Y_AXIS; break;
+      case BACK:  axis = Y_AXIS; dir = -1; break;
+    #endif
     default: return;
   }
 
   if (probe_top_at_edge) {
-    // Probe top nearest the side we are probing
-    current_position[axis] = m.obj_center[axis] + (-dir) * (dimensions[axis] / 2 - m.nozzle_outer_dimension[axis]);
-    calibration_move();
-    m.obj_side[TOP] = measure(Z_AXIS, -1, true, &m.backlash[TOP], uncertainty);
-    m.obj_center.z = m.obj_side[TOP] - dimensions.z / 2;
+    #if AXIS_CAN_CALIBRATE(Z)
+      // Probe top nearest the side we are probing
+      current_position[axis] = m.obj_center[axis] + (-dir) * (dimensions[axis] / 2 - m.nozzle_outer_dimension[axis]);
+      calibration_move();
+      m.obj_side[TOP] = measure(Z_AXIS, -1, true, &m.backlash[TOP], uncertainty);
+      m.obj_center.z = m.obj_side[TOP] - dimensions.z / 2;
+    #endif
   }
 
-  // Move to safe distance to the side of the calibration object
-  current_position[axis] = m.obj_center[axis] + (-dir) * (dimensions[axis] / 2 + m.nozzle_outer_dimension[axis] / 2 + uncertainty);
-  calibration_move();
+  if (AXIS_CAN_CALIBRATE(X) && axis == X_AXIS || AXIS_CAN_CALIBRATE(Y) && axis == Y_AXIS) {
+    // Move to safe distance to the side of the calibration object
+    current_position[axis] = m.obj_center[axis] + (-dir) * (dimensions[axis] / 2 + m.nozzle_outer_dimension[axis] / 2 + uncertainty);
+    calibration_move();
 
-  // Plunge below the side of the calibration object and measure
-  current_position.z = m.obj_side[TOP] - CALIBRATION_NOZZLE_TIP_HEIGHT * 0.7;
-  calibration_move();
-  const float measurement = measure(axis, dir, true, &m.backlash[side], uncertainty);
-  m.obj_center[axis] = measurement + dir * (dimensions[axis] / 2 + m.nozzle_outer_dimension[axis] / 2);
-  m.obj_side[side] = measurement;
+    // Plunge below the side of the calibration object and measure
+    current_position.z = m.obj_side[TOP] - (CALIBRATION_NOZZLE_TIP_HEIGHT) * 0.7f;
+    calibration_move();
+    const float measurement = measure(axis, dir, true, &m.backlash[side], uncertainty);
+    m.obj_center[axis] = measurement + dir * (dimensions[axis] / 2 + m.nozzle_outer_dimension[axis] / 2);
+    m.obj_side[side] = measurement;
+  }
 }
 
 /**
@@ -252,7 +277,7 @@ inline void probe_side(measurements_t &m, const float uncertainty, const side_t
  *   uncertainty        in     - How far away from the calibration object to begin probing
  */
 inline void probe_sides(measurements_t &m, const float uncertainty) {
-  #ifdef CALIBRATION_MEASURE_AT_TOP_EDGES
+  #if ENABLED(CALIBRATION_MEASURE_AT_TOP_EDGES)
     constexpr bool probe_top_at_edge = true;
   #else
     // Probing at the exact center only works if the center is flat. Probing on a washer
@@ -261,18 +286,18 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
     probe_side(m, uncertainty, TOP);
   #endif
 
-  #ifdef CALIBRATION_MEASURE_RIGHT
+  #if ENABLED(CALIBRATION_MEASURE_RIGHT)
     probe_side(m, uncertainty, RIGHT, probe_top_at_edge);
   #endif
 
-  #ifdef CALIBRATION_MEASURE_FRONT
+  #if ENABLED(CALIBRATION_MEASURE_FRONT)
     probe_side(m, uncertainty, FRONT, probe_top_at_edge);
   #endif
 
-  #ifdef CALIBRATION_MEASURE_LEFT
+  #if ENABLED(CALIBRATION_MEASURE_LEFT)
     probe_side(m, uncertainty, LEFT,  probe_top_at_edge);
   #endif
-  #ifdef CALIBRATION_MEASURE_BACK
+  #if ENABLED(CALIBRATION_MEASURE_BACK)
     probe_side(m, uncertainty, BACK,  probe_top_at_edge);
   #endif
 
@@ -313,7 +338,9 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
 #if ENABLED(CALIBRATION_REPORTING)
   inline void report_measured_faces(const measurements_t &m) {
     SERIAL_ECHOLNPGM("Sides:");
-    SERIAL_ECHOLNPAIR("  Top: ", m.obj_side[TOP]);
+    #if AXIS_CAN_CALIBRATE(Z)
+      SERIAL_ECHOLNPAIR("  Top: ", m.obj_side[TOP]);
+    #endif
     #if ENABLED(CALIBRATION_MEASURE_LEFT)
       SERIAL_ECHOLNPAIR("  Left: ", m.obj_side[LEFT]);
     #endif
@@ -343,19 +370,25 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
 
   inline void report_measured_backlash(const measurements_t &m) {
     SERIAL_ECHOLNPGM("Backlash:");
-    #if ENABLED(CALIBRATION_MEASURE_LEFT)
-      SERIAL_ECHOLNPAIR("  Left: ", m.backlash[LEFT]);
+    #if AXIS_CAN_CALIBRATE(X)
+      #if ENABLED(CALIBRATION_MEASURE_LEFT)
+        SERIAL_ECHOLNPAIR("  Left: ", m.backlash[LEFT]);
+      #endif
+      #if ENABLED(CALIBRATION_MEASURE_RIGHT)
+        SERIAL_ECHOLNPAIR("  Right: ", m.backlash[RIGHT]);
+      #endif
     #endif
-    #if ENABLED(CALIBRATION_MEASURE_RIGHT)
-      SERIAL_ECHOLNPAIR("  Right: ", m.backlash[RIGHT]);
+    #if AXIS_CAN_CALIBRATE(Y)
+      #if ENABLED(CALIBRATION_MEASURE_FRONT)
+        SERIAL_ECHOLNPAIR("  Front: ", m.backlash[FRONT]);
+      #endif
+      #if ENABLED(CALIBRATION_MEASURE_BACK)
+        SERIAL_ECHOLNPAIR("  Back: ", m.backlash[BACK]);
+      #endif
     #endif
-    #if ENABLED(CALIBRATION_MEASURE_FRONT)
-      SERIAL_ECHOLNPAIR("  Front: ", m.backlash[FRONT]);
+    #if AXIS_CAN_CALIBRATE(Z)
+      SERIAL_ECHOLNPAIR("  Top: ", m.backlash[TOP]);
     #endif
-    #if ENABLED(CALIBRATION_MEASURE_BACK)
-      SERIAL_ECHOLNPAIR("  Back: ", m.backlash[BACK]);
-    #endif
-    SERIAL_ECHOLNPAIR("  Top: ", m.backlash[TOP]);
     SERIAL_EOL();
   }
 
@@ -369,7 +402,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
     #if HAS_Y_CENTER
       SERIAL_ECHOLNPAIR_P(SP_Y_STR, m.pos_error.y);
     #endif
-    SERIAL_ECHOLNPAIR_P(SP_Z_STR, m.pos_error.z);
+    if (AXIS_CAN_CALIBRATE(Z)) SERIAL_ECHOLNPAIR_P(SP_Z_STR, m.pos_error.z);
     SERIAL_EOL();
   }
 
@@ -417,6 +450,7 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) {
     probe_sides(m, uncertainty);
 
     #if ENABLED(BACKLASH_GCODE)
+
       #if HAS_X_CENTER
         backlash.distance_mm.x = (m.backlash[LEFT] + m.backlash[RIGHT]) / 2;
       #elif ENABLED(CALIBRATION_MEASURE_LEFT)
@@ -433,18 +467,18 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) {
         backlash.distance_mm.y = m.backlash[BACK];
       #endif
 
-      backlash.distance_mm.z = m.backlash[TOP];
+      if (AXIS_CAN_CALIBRATE(Z)) backlash.distance_mm.z = m.backlash[TOP];
     #endif
   }
 
   #if ENABLED(BACKLASH_GCODE)
     // Turn on backlash compensation and move in all
-    // directions to take up any backlash
+    // allowed directions to take up any backlash
     {
       // New scope for TEMPORARY_BACKLASH_CORRECTION
       TEMPORARY_BACKLASH_CORRECTION(all_on);
       TEMPORARY_BACKLASH_SMOOTHING(0.0f);
-      const xyz_float_t move = { 3, 3, 3 };
+      const xyz_float_t move = { AXIS_CAN_CALIBRATE(X) * 3, AXIS_CAN_CALIBRATE(Y) * 3, AXIS_CAN_CALIBRATE(Z) * 3 };
       current_position += move; calibration_move();
       current_position -= move; calibration_move();
     }
@@ -482,26 +516,18 @@ inline void calibrate_toolhead(measurements_t &m, const float uncertainty, const
 
   // Adjust the hotend offset
   #if HAS_HOTEND_OFFSET
-    #if HAS_X_CENTER
-      hotend_offset[extruder].x += m.pos_error.x;
-    #endif
-    #if HAS_Y_CENTER
-      hotend_offset[extruder].y += m.pos_error.y;
-    #endif
-    hotend_offset[extruder].z += m.pos_error.z;
+    if (ENABLED(HAS_X_CENTER) && AXIS_CAN_CALIBRATE(X)) hotend_offset[extruder].x += m.pos_error.x;
+    if (ENABLED(HAS_Y_CENTER) && AXIS_CAN_CALIBRATE(Y)) hotend_offset[extruder].y += m.pos_error.y;
+                             if (AXIS_CAN_CALIBRATE(Z)) hotend_offset[extruder].z += m.pos_error.z;
     normalize_hotend_offsets();
   #endif
 
   // Correct for positional error, so the object
   // is at the known actual spot
   planner.synchronize();
-  #if HAS_X_CENTER
-    update_measurements(m, X_AXIS);
-  #endif
-  #if HAS_Y_CENTER
-    update_measurements(m, Y_AXIS);
-  #endif
-  update_measurements(m, Z_AXIS);
+  if (ENABLED(HAS_X_CENTER) && AXIS_CAN_CALIBRATE(X)) update_measurements(m, X_AXIS);
+  if (ENABLED(HAS_Y_CENTER) && AXIS_CAN_CALIBRATE(Y)) update_measurements(m, Y_AXIS);
+                           if (AXIS_CAN_CALIBRATE(Z)) update_measurements(m, Z_AXIS);
 
   sync_plan_position();
 }
diff --git a/Marlin/src/gcode/calibrate/M425.cpp b/Marlin/src/gcode/calibrate/M425.cpp
index 41c80daf7c..980152a4b1 100644
--- a/Marlin/src/gcode/calibrate/M425.cpp
+++ b/Marlin/src/gcode/calibrate/M425.cpp
@@ -47,7 +47,7 @@ void GcodeSuite::M425() {
   bool noArgs = true;
 
   LOOP_XYZ(a) {
-    if (parser.seen(XYZ_CHAR(a))) {
+    if (CAN_CALIBRATE(a) && parser.seen(XYZ_CHAR(a))) {
       planner.synchronize();
       backlash.distance_mm[a] = parser.has_value() ? parser.value_linear_units() : backlash.get_measurement(AxisEnum(a));
       noArgs = false;
@@ -74,7 +74,7 @@ void GcodeSuite::M425() {
     SERIAL_ECHOLNPGM("active:");
     SERIAL_ECHOLNPAIR("  Correction Amount/Fade-out:     F", backlash.get_correction(), " (F1.0 = full, F0.0 = none)");
     SERIAL_ECHOPGM("  Backlash Distance (mm):        ");
-    LOOP_XYZ(a) {
+    LOOP_XYZ(a) if (CAN_CALIBRATE(a)) {
       SERIAL_CHAR(' ', XYZ_CHAR(a));
       SERIAL_ECHO(backlash.distance_mm[a]);
       SERIAL_EOL();
@@ -87,7 +87,7 @@ void GcodeSuite::M425() {
     #if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
       SERIAL_ECHOPGM("  Average measured backlash (mm):");
       if (backlash.has_any_measurement()) {
-        LOOP_XYZ(a) if (backlash.has_measurement(AxisEnum(a))) {
+        LOOP_XYZ(a) if (CAN_CALIBRATE(a) && backlash.has_measurement(AxisEnum(a))) {
           SERIAL_CHAR(' ', XYZ_CHAR(a));
           SERIAL_ECHO(backlash.get_measurement(AxisEnum(a)));
         }
diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h
index d9db986466..9ea298f02d 100644
--- a/Marlin/src/inc/Conditionals_post.h
+++ b/Marlin/src/inc/Conditionals_post.h
@@ -139,6 +139,19 @@
   #define CORESIGN(n) (ANY(COREYX, COREZX, COREZY) ? (-(n)) : (n))
 #endif
 
+// Calibration codes only for non-core axes
+#if EITHER(BACKLASH_GCODE, CALIBRATION_GCODE)
+  #if IS_CORE
+    #define X_AXIS_INDEX 0
+    #define Y_AXIS_INDEX 1
+    #define Z_AXIS_INDEX 2
+    #define CAN_CALIBRATE(A,B) (A##_AXIS_INDEX == B##_INDEX)
+  #else
+    #define CAN_CALIBRATE(...) 1
+  #endif
+#endif
+#define AXIS_CAN_CALIBRATE(A) CAN_CALIBRATE(A,NORMAL_AXIS)
+
 /**
  * No adjustable bed on non-cartesians
  */
diff --git a/Marlin/src/inc/MarlinConfig.h b/Marlin/src/inc/MarlinConfig.h
index d32506702e..c1655015e0 100644
--- a/Marlin/src/inc/MarlinConfig.h
+++ b/Marlin/src/inc/MarlinConfig.h
@@ -35,11 +35,12 @@
 #include "Conditionals_post.h"
 #include HAL_PATH(../HAL, inc/Conditionals_post.h)
 
+#include "../core/types.h"  // Ahead of sanity-checks
+
 #include "SanityCheck.h"
 #include HAL_PATH(../HAL, inc/SanityCheck.h)
 
 // Include all core headers
-#include "../core/types.h"
 #include "../core/language.h"
 #include "../core/utility.h"
 #include "../core/serial.h"
diff --git a/Marlin/src/lcd/menu/menu_backlash.cpp b/Marlin/src/lcd/menu/menu_backlash.cpp
index ad9c51d4cf..720694bfff 100644
--- a/Marlin/src/lcd/menu/menu_backlash.cpp
+++ b/Marlin/src/lcd/menu/menu_backlash.cpp
@@ -39,9 +39,9 @@ void menu_backlash() {
   EDIT_ITEM_FAST(percent, MSG_BACKLASH_CORRECTION, &backlash.correction, all_off, all_on);
 
   #define EDIT_BACKLASH_DISTANCE(N) EDIT_ITEM_FAST(float43, MSG_BACKLASH_##N, &backlash.distance_mm[_AXIS(N)], 0.0f, 9.9f);
-  EDIT_BACKLASH_DISTANCE(A);
-  EDIT_BACKLASH_DISTANCE(B);
-  EDIT_BACKLASH_DISTANCE(C);
+  if (AXIS_CAN_CALIBRATE(A)) EDIT_BACKLASH_DISTANCE(A);
+  if (AXIS_CAN_CALIBRATE(B)) EDIT_BACKLASH_DISTANCE(B);
+  if (AXIS_CAN_CALIBRATE(C)) EDIT_BACKLASH_DISTANCE(C);
 
   #ifdef BACKLASH_SMOOTHING_MM
     EDIT_ITEM_FAST(float43, MSG_BACKLASH_SMOOTHING, &backlash.smoothing_mm, 0.0f, 9.9f);