diff --git a/Marlin/src/feature/power_loss_recovery.cpp b/Marlin/src/feature/power_loss_recovery.cpp
index 1c38e4f97ae2abcd2880fb44daf5085521b795b1..eb25bd4274ec6c2e149073dce93bb07f8bb95629 100644
--- a/Marlin/src/feature/power_loss_recovery.cpp
+++ b/Marlin/src/feature/power_loss_recovery.cpp
@@ -175,7 +175,9 @@ void PrintJobRecovery::save(const bool force/*=false*/, const bool save_queue/*=
       info.active_extruder = active_extruder;
     #endif
 
-    HOTEND_LOOP() info.target_temperature[e] = thermalManager.temp_hotend[e].target;
+    #if EXTRUDERS
+      HOTEND_LOOP() info.target_temperature[e] = thermalManager.temp_hotend[e].target;
+    #endif
 
     #if HAS_HEATED_BED
       info.target_temperature_bed = thermalManager.temp_bed.target;
@@ -297,17 +299,19 @@ void PrintJobRecovery::resume() {
   #endif
 
   // Restore all hotend temperatures
-  HOTEND_LOOP() {
-    const int16_t et = info.target_temperature[e];
-    if (et) {
-      #if HOTENDS > 1
-        sprintf_P(cmd, PSTR("T%i"), e);
+  #if HOTENDS
+    HOTEND_LOOP() {
+      const int16_t et = info.target_temperature[e];
+      if (et) {
+        #if HOTENDS > 1
+          sprintf_P(cmd, PSTR("T%i"), e);
+          gcode.process_subcommands_now(cmd);
+        #endif
+        sprintf_P(cmd, PSTR("M109 S%i"), et);
         gcode.process_subcommands_now(cmd);
-      #endif
-      sprintf_P(cmd, PSTR("M109 S%i"), et);
-      gcode.process_subcommands_now(cmd);
+      }
     }
-  }
+  #endif
 
   // Restore print cooling fan speeds
   FANS_LOOP(i) {
@@ -452,12 +456,14 @@ void PrintJobRecovery::resume() {
           DEBUG_ECHOLNPAIR("active_extruder: ", int(info.active_extruder));
         #endif
 
-        DEBUG_ECHOPGM("target_temperature: ");
-        HOTEND_LOOP() {
-          DEBUG_ECHO(info.target_temperature[e]);
-          if (e < HOTENDS - 1) DEBUG_CHAR(',');
-        }
-        DEBUG_EOL();
+        #if HOTENDS
+          DEBUG_ECHOPGM("target_temperature: ");
+          HOTEND_LOOP() {
+            DEBUG_ECHO(info.target_temperature[e]);
+            if (e < HOTENDS - 1) DEBUG_CHAR(',');
+          }
+          DEBUG_EOL();
+        #endif
 
         #if HAS_HEATED_BED
           DEBUG_ECHOLNPAIR("target_temperature_bed: ", info.target_temperature_bed);
diff --git a/Marlin/src/feature/power_loss_recovery.h b/Marlin/src/feature/power_loss_recovery.h
index 34322243fd036ad6533cb6a24cb68152af519f61..2cfde035066645450883b01da4b0e4c0c3456249 100644
--- a/Marlin/src/feature/power_loss_recovery.h
+++ b/Marlin/src/feature/power_loss_recovery.h
@@ -59,7 +59,9 @@ typedef struct {
     uint8_t active_extruder;
   #endif
 
-  int16_t target_temperature[HOTENDS];
+  #if HOTENDS
+    int16_t target_temperature[HOTENDS];
+  #endif
 
   #if HAS_HEATED_BED
     int16_t target_temperature_bed;
diff --git a/Marlin/src/gcode/config/M221.cpp b/Marlin/src/gcode/config/M221.cpp
index cbb31628af6430f2cc467119dadaabab3e0bb508..116ce776b2ea85e6ae3bb1ff91827a6c2a6936af 100644
--- a/Marlin/src/gcode/config/M221.cpp
+++ b/Marlin/src/gcode/config/M221.cpp
@@ -23,6 +23,8 @@
 #include "../gcode.h"
 #include "../../module/planner.h"
 
+#if EXTRUDERS
+
 /**
  * M221: Set extrusion percentage (M221 T0 S95)
  */
@@ -44,3 +46,5 @@ void GcodeSuite::M221() {
     SERIAL_EOL();
   }
 }
+
+#endif // EXTRUDERS
diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp
index 8ad818c925c5d613ca2606863b23817691354bcb..680fa3597498d9b71bd217eb49ce233dfee4008c 100644
--- a/Marlin/src/gcode/gcode.cpp
+++ b/Marlin/src/gcode/gcode.cpp
@@ -400,8 +400,18 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
         case 100: M100(); break;                                  // M100: Free Memory Report
       #endif
 
-      case 104: M104(); break;                                    // M104: Set hot end temperature
-      case 109: M109(); break;                                    // M109: Wait for hotend temperature to reach target
+      #if EXTRUDERS
+        case 104: M104(); break;                                  // M104: Set hot end temperature
+        case 109: M109(); break;                                  // M109: Wait for hotend temperature to reach target
+      #endif
+
+      case 105: M105(); return;                                   // M105: Report Temperatures (and say "ok")
+
+      #if FAN_COUNT > 0
+        case 106: M106(); break;                                  // M106: Fan On
+        case 107: M107(); break;                                  // M107: Fan Off
+      #endif
+
       case 110: M110(); break;                                    // M110: Set Current Line Number
       case 111: M111(); break;                                    // M111: Set debug level
 
@@ -410,7 +420,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
         case 112: M112(); break;                                  // M112: Full Shutdown
         case 410: M410(); break;                                  // M410: Quickstop - Abort all the planned moves.
         #if ENABLED(HOST_PROMPT_SUPPORT)
-          case 876: M876(); break;                                  // M876: Handle Host prompt responses
+          case 876: M876(); break;                                // M876: Handle Host prompt responses
         #endif
       #else
         case 108: case 112: case 410:
@@ -434,17 +444,10 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
         //case 191: M191(); break;                                // M191: Wait for chamber temperature to reach target
       #endif
 
-      case 105: M105(); return;                                   // M105: Report Temperatures (and say "ok")
-
       #if ENABLED(AUTO_REPORT_TEMPERATURES) && HAS_TEMP_SENSOR
         case 155: M155(); break;                                  // M155: Set temperature auto-report interval
       #endif
 
-      #if FAN_COUNT > 0
-        case 106: M106(); break;                                  // M106: Fan On
-        case 107: M107(); break;                                  // M107: Fan Off
-      #endif
-
       #if ENABLED(PARK_HEAD_ON_PAUSE)
         case 125: M125(); break;                                  // M125: Store current position and move to filament change position
       #endif
@@ -481,7 +484,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
       case 120: M120(); break;                                    // M120: Enable endstops
       case 121: M121(); break;                                    // M121: Disable endstops
 
-      #if HAS_LCD_MENU
+      #if HOTENDS && HAS_LCD_MENU
         case 145: M145(); break;                                  // M145: Set material heatup parameters
       #endif
 
@@ -553,7 +556,11 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
       #endif
 
       case 220: M220(); break;                                    // M220: Set Feedrate Percentage: S<percent> ("FR" on your LCD)
-      case 221: M221(); break;                                    // M221: Set Flow Percentage
+
+      #if EXTRUDERS
+        case 221: M221(); break;                                  // M221: Set Flow Percentage
+      #endif
+
       case 226: M226(); break;                                    // M226: Wait until a pin reaches a state
 
       #if HAS_SERVOS
diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h
index c9b0cec2af3345fac25be8e6396b83a59ccf0573..8840d40d6a41c6895d75d93375d70e525dad79b6 100644
--- a/Marlin/src/gcode/gcode.h
+++ b/Marlin/src/gcode/gcode.h
@@ -543,10 +543,17 @@ private:
     static void M100();
   #endif
 
-  static void M104();
+  #if EXTRUDERS
+    static void M104();
+    static void M109();
+  #endif
+
   static void M105();
-  static void M106();
-  static void M107();
+
+  #if FAN_COUNT > 0
+    static void M106();
+    static void M107();
+  #endif
 
   #if DISABLED(EMERGENCY_PARSER)
     static void M108();
@@ -557,8 +564,6 @@ private:
     #endif
   #endif
 
-  static void M109();
-
   static void M110();
   static void M111();
 
@@ -599,7 +604,7 @@ private:
     //static void M191();
   #endif
 
-  #if HAS_LCD_MENU
+  #if HOTENDS && HAS_LCD_MENU
     static void M145();
   #endif
 
@@ -660,7 +665,11 @@ private:
   #endif
 
   static void M220();
-  static void M221();
+
+  #if EXTRUDERS
+    static void M221();
+  #endif
+
   static void M226();
 
   #if ENABLED(PHOTO_GCODE)
diff --git a/Marlin/src/gcode/lcd/M145.cpp b/Marlin/src/gcode/lcd/M145.cpp
index 693a32d242c671f0601018097720065e7bc2a602..297ece268e0d12431854b019d949e01cb6c63e10 100644
--- a/Marlin/src/gcode/lcd/M145.cpp
+++ b/Marlin/src/gcode/lcd/M145.cpp
@@ -22,7 +22,7 @@
 
 #include "../../inc/MarlinConfig.h"
 
-#if HAS_LCD_MENU
+#if HOTENDS && HAS_LCD_MENU
 
 #include "../gcode.h"
 #include "../../lcd/ultralcd.h"
@@ -58,4 +58,4 @@ void GcodeSuite::M145() {
   }
 }
 
-#endif // HAS_LCD_MENU
+#endif // HOTENDS && HAS_LCD_MENU
diff --git a/Marlin/src/gcode/temperature/M104_M109.cpp b/Marlin/src/gcode/temperature/M104_M109.cpp
index f4259abff9b0bbbaf30af254785117b94f6c61e7..86da46a89e34a58688376029046457e35ae37652 100644
--- a/Marlin/src/gcode/temperature/M104_M109.cpp
+++ b/Marlin/src/gcode/temperature/M104_M109.cpp
@@ -20,6 +20,10 @@
  *
  */
 
+#include "../../inc/MarlinConfigPre.h"
+
+#if EXTRUDERS
+
 #include "../gcode.h"
 #include "../../module/temperature.h"
 #include "../../module/motion.h"
@@ -138,3 +142,5 @@ void GcodeSuite::M109() {
   if (set_temp)
     (void)thermalManager.wait_for_hotend(target_extruder, no_wait_for_cooling);
 }
+
+#endif // EXTRUDERS
diff --git a/Marlin/src/inc/Conditionals_adv.h b/Marlin/src/inc/Conditionals_adv.h
index 37ec8c09aeeffea319591583464789fba683d375..b9b8855428e52ece536c6252c7359374d6638700 100644
--- a/Marlin/src/inc/Conditionals_adv.h
+++ b/Marlin/src/inc/Conditionals_adv.h
@@ -26,6 +26,34 @@
  * Defines that depend on advanced configuration.
  */
 
+#if EXTRUDERS == 0
+  #define NO_VOLUMETRICS
+  #undef TEMP_SENSOR_0
+  #undef TEMP_SENSOR_1
+  #undef TEMP_SENSOR_2
+  #undef TEMP_SENSOR_3
+  #undef TEMP_SENSOR_4
+  #undef TEMP_SENSOR_5
+  #undef FWRETRACT
+  #undef PIDTEMP
+  #undef AUTOTEMP
+  #undef PID_EXTRUSION_SCALING
+  #undef LIN_ADVANCE
+  #undef FILAMENT_RUNOUT_SENSOR
+  #undef ADVANCED_PAUSE_FEATURE
+  #undef FILAMENT_RUNOUT_DISTANCE_MM
+  #undef FILAMENT_LOAD_UNLOAD_GCODES
+  #undef DISABLE_INACTIVE_EXTRUDER
+  #undef FILAMENT_LOAD_UNLOAD_GCODES
+  #undef EXTRUDER_RUNOUT_PREVENT
+  #undef PREVENT_COLD_EXTRUSION
+  #undef PREVENT_LENGTHY_EXTRUDE
+  #undef THERMAL_PROTECTION_HOTENDS
+  #undef THERMAL_PROTECTION_PERIOD
+  #undef WATCH_TEMP_PERIOD
+  #undef SHOW_TEMP_ADC_VALUES
+#endif
+
 #define HAS_CUTTER EITHER(SPINDLE_FEATURE, LASER_FEATURE)
 
 #if !defined(__AVR__) || !defined(USBCON)
diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h
index 3731b14512e933b3b5666172d41d29e7f7de4bc2..4971a74107ff08afe486bea0f0606b611b01e1f5 100644
--- a/Marlin/src/inc/Conditionals_post.h
+++ b/Marlin/src/inc/Conditionals_post.h
@@ -43,16 +43,6 @@
   #define NOT_A_PIN 0 // For PINS_DEBUGGING
 #endif
 
-#if EXTRUDERS == 0
-  #define NO_VOLUMETRICS
-  #undef FWRETRACT
-  #undef LIN_ADVANCE
-  #undef ADVANCED_PAUSE_FEATURE
-  #undef DISABLE_INACTIVE_EXTRUDER
-  #undef EXTRUDER_RUNOUT_PREVENT
-  #undef FILAMENT_LOAD_UNLOAD_GCODES
-#endif
-
 #define HAS_CLASSIC_JERK (IS_KINEMATIC || DISABLED(JUNCTION_DEVIATION))
 
 /**
@@ -1047,6 +1037,10 @@
 #define BED_OR_CHAMBER (HAS_HEATED_BED || HAS_TEMP_CHAMBER)
 #define HAS_TEMP_SENSOR (HAS_TEMP_HOTEND || BED_OR_CHAMBER)
 
+#if !HAS_TEMP_SENSOR
+  #undef AUTO_REPORT_TEMPERATURES
+#endif
+
 // PID heating
 #if !HAS_HEATED_BED
   #undef PIDTEMPBED
diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h
index eaec7529ef5bd937e996ecfe550c1c77b8a9d6f9..f6c8fe2f94e9f5565caaa8649177052704b719d1 100644
--- a/Marlin/src/inc/SanityCheck.h
+++ b/Marlin/src/inc/SanityCheck.h
@@ -1476,8 +1476,8 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
   #error "E0_STEP_PIN or E0_DIR_PIN not defined for this board."
 #elif ( !(defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__)) && (!PIN_EXISTS(E0_STEP, E0_DIR) || !HAS_E0_ENABLE))
   #error "E0_STEP_PIN, E0_DIR_PIN, or E0_ENABLE_PIN not defined for this board."
-#elif TEMP_SENSOR_0 == 0
-  #error "TEMP_SENSOR_0 is required."
+#elif EXTRUDERS && TEMP_SENSOR_0 == 0
+  #error "TEMP_SENSOR_0 is required with any extruders."
 #endif
 
 // Pins are required for heaters
diff --git a/Marlin/src/lcd/HD44780/ultralcd_HD44780.cpp b/Marlin/src/lcd/HD44780/ultralcd_HD44780.cpp
index b7ebc111a5e64e3db1900eebf196b18a104e7833..c08067fb6bcc20bea5cb01d1ac51f0b4f9b235de 100644
--- a/Marlin/src/lcd/HD44780/ultralcd_HD44780.cpp
+++ b/Marlin/src/lcd/HD44780/ultralcd_HD44780.cpp
@@ -866,7 +866,11 @@ void MarlinUI::draw_status_screen() {
           char c;
           uint16_t per;
           #if HAS_FAN0
-            if (blink || thermalManager.fan_speed_scaler[0] < 128) {
+            if (true
+              #if EXTRUDERS
+                && (blink || thermalManager.fan_speed_scaler[0] < 128)
+              #endif
+            ) {
               uint16_t spd = thermalManager.fan_speed[0];
               if (blink) c = 'F';
               #if ENABLED(ADAPTIVE_FAN_SLOWING)
@@ -877,8 +881,10 @@ void MarlinUI::draw_status_screen() {
             else
           #endif
             {
-              c = 'E';
-              per = planner.flow_percentage[0];
+              #if EXTRUDERS
+                c = 'E';
+                per = planner.flow_percentage[0];
+              #endif
             }
           lcd_put_wchar(c);
           lcd_put_u8str(i16tostr3(per));
diff --git a/Marlin/src/lcd/dogm/dogm_Statusscreen.h b/Marlin/src/lcd/dogm/dogm_Statusscreen.h
index aff3a3ae1c8e5fa90953b8ba6be8dfe85d34d8c2..46fc9f7f196b049792339e7351db71c1c02d7124 100644
--- a/Marlin/src/lcd/dogm/dogm_Statusscreen.h
+++ b/Marlin/src/lcd/dogm/dogm_Statusscreen.h
@@ -69,10 +69,28 @@
     //
     #if HAS_HEATED_BED && HOTENDS <= 4
 
-      #if HOTENDS == 1
+      #if HOTENDS == 0
+
+        #define STATUS_HEATERS_WIDTH 96
+
+        const unsigned char status_heaters_bmp[] PROGMEM = {
+          B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000100,B00010000,B01000000,
+          B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000010,B00001000,B00100000,
+          B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000010,B00001000,B00100000,
+          B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000100,B00010000,B01000000,
+          B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001000,B00100000,B10000000,
+          B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00010000,B01000001,B00000000,
+          B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00010000,B01000001,B00000000,
+          B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00001000,B00100000,B10000000,
+          B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000100,B00010000,B01000000,
+          B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
+          B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011111,B11111111,B11111000,
+          B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00011111,B11111111,B11111000
+        };
+
+      #elif HOTENDS == 1
 
         #define STATUS_HEATERS_WIDTH 96
-        #define STATUS_BED_TEXT_X   (STATUS_HEATERS_WIDTH - 10)
 
         const unsigned char status_heaters_bmp[] PROGMEM = {
           B00011111,B11100000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000100,B00010000,B01000000,
@@ -92,7 +110,6 @@
       #elif HOTENDS == 2
 
         #define STATUS_HEATERS_WIDTH 96
-        #define STATUS_BED_TEXT_X   (STATUS_HEATERS_WIDTH - 10)
 
         const unsigned char status_heaters_bmp[] PROGMEM = {
           B00011111,B11100000,B00000000,B00011111,B11100000,B00000000,B00000000,B00000000,B00000000,B00000100,B00010000,B01000000,
@@ -112,7 +129,6 @@
       #elif HOTENDS == 3
 
         #define STATUS_HEATERS_WIDTH 96
-        #define STATUS_BED_TEXT_X   (STATUS_HEATERS_WIDTH - 10)
 
         const unsigned char status_heaters_bmp[] PROGMEM = {
           B00011111,B11100000,B00000000,B00011111,B11100000,B00000000,B00011111,B11100000,B00000000,B00000100,B00010000,B01000000,
@@ -132,7 +148,6 @@
       #else // HOTENDS > 3
 
         #define STATUS_HEATERS_WIDTH 120
-        #define STATUS_BED_TEXT_X   (STATUS_HEATERS_WIDTH - 10)
 
         const unsigned char status_heaters_bmp[] PROGMEM = {
           B00011111,B11100000,B00000000,B00011111,B11100000,B00000000,B00011111,B11100000,B00000000,B00011111,B11100000,B00000000,B00000100,B00010000,B01000000,
@@ -151,9 +166,15 @@
 
       #endif // HOTENDS
 
+      #define STATUS_BED_TEXT_X (STATUS_HEATERS_WIDTH - 10)
+
     #else // !HAS_HEATED_BED || HOTENDS > 3
 
-      #if HOTENDS == 1
+      #if HOTENDS == 0
+
+        #define STATUS_HEATERS_WIDTH  0
+
+      #elif HOTENDS == 1
 
         #define STATUS_HEATERS_WIDTH  12
 
@@ -229,7 +250,7 @@
           B00000011,B00000000,B00000000,B00000011,B00000000,B00000000,B00000011,B00000000,B00000000,B00000011,B00000000
         };
 
-      #elif HOTENDS > 4
+      #else // HOTENDS > 4
 
         #define STATUS_HEATERS_WIDTH  108
 
@@ -304,105 +325,101 @@
 
         #endif
 
-      #else
-
-        #if HOTENDS >= 2
-
-          #ifdef STATUS_HOTEND_ANIM
+      #elif HOTENDS >= 2
 
-            const unsigned char status_hotend1_a_bmp[] PROGMEM = {
-              B00011111,B11100000,
-              B00111111,B11110000,
-              B00111110,B11110000,
-              B00111100,B11110000,
-              B00011010,B11100000,
-              B00011110,B11100000,
-              B00111110,B11110000,
-              B00111110,B11110000,
-              B00111110,B11110000,
-              B00001111,B11000000,
-              B00000111,B10000000,
-              B00000011,B00000000
-            };
+        #ifdef STATUS_HOTEND_ANIM
 
-            const unsigned char status_hotend1_b_bmp[] PROGMEM = {
-              B00011111,B11100000,
-              B00100000,B00010000,
-              B00100001,B00010000,
-              B00100011,B00010000,
-              B00010101,B00100000,
-              B00010001,B00100000,
-              B00100001,B00010000,
-              B00100001,B00010000,
-              B00110001,B00110000,
-              B00001000,B01000000,
-              B00000100,B10000000,
-              B00000011,B00000000
-            };
+          const unsigned char status_hotend1_a_bmp[] PROGMEM = {
+            B00011111,B11100000,
+            B00111111,B11110000,
+            B00111110,B11110000,
+            B00111100,B11110000,
+            B00011010,B11100000,
+            B00011110,B11100000,
+            B00111110,B11110000,
+            B00111110,B11110000,
+            B00111110,B11110000,
+            B00001111,B11000000,
+            B00000111,B10000000,
+            B00000011,B00000000
+          };
 
-            const unsigned char status_hotend2_a_bmp[] PROGMEM = {
-              B00011111,B11100000,
-              B00111111,B11110000,
-              B00111100,B11110000,
-              B00111011,B01110000,
-              B00011111,B01100000,
-              B00011110,B11100000,
-              B00111101,B11110000,
-              B00111011,B11110000,
-              B00111000,B01110000,
-              B00001111,B11000000,
-              B00000111,B10000000,
-              B00000011,B00000000
-            };
+          const unsigned char status_hotend1_b_bmp[] PROGMEM = {
+            B00011111,B11100000,
+            B00100000,B00010000,
+            B00100001,B00010000,
+            B00100011,B00010000,
+            B00010101,B00100000,
+            B00010001,B00100000,
+            B00100001,B00010000,
+            B00100001,B00010000,
+            B00110001,B00110000,
+            B00001000,B01000000,
+            B00000100,B10000000,
+            B00000011,B00000000
+          };
 
-            const unsigned char status_hotend2_b_bmp[] PROGMEM = {
-              B00011111,B11100000,
-              B00100000,B00010000,
-              B00100011,B00010000,
-              B00100100,B10010000,
-              B00010000,B10100000,
-              B00010001,B00100000,
-              B00100010,B00010000,
-              B00100100,B00010000,
-              B00110111,B10110000,
-              B00001000,B01000000,
-              B00000100,B10000000,
-              B00000011,B00000000
-            };
+          const unsigned char status_hotend2_a_bmp[] PROGMEM = {
+            B00011111,B11100000,
+            B00111111,B11110000,
+            B00111100,B11110000,
+            B00111011,B01110000,
+            B00011111,B01100000,
+            B00011110,B11100000,
+            B00111101,B11110000,
+            B00111011,B11110000,
+            B00111000,B01110000,
+            B00001111,B11000000,
+            B00000111,B10000000,
+            B00000011,B00000000
+          };
 
-          #else
+          const unsigned char status_hotend2_b_bmp[] PROGMEM = {
+            B00011111,B11100000,
+            B00100000,B00010000,
+            B00100011,B00010000,
+            B00100100,B10010000,
+            B00010000,B10100000,
+            B00010001,B00100000,
+            B00100010,B00010000,
+            B00100100,B00010000,
+            B00110111,B10110000,
+            B00001000,B01000000,
+            B00000100,B10000000,
+            B00000011,B00000000
+          };
 
-            const unsigned char status_hotend1_a_bmp[] PROGMEM = {
-              B00011111,B11100000,
-              B00111110,B11110000,
-              B00111100,B11110000,
-              B00111010,B11110000,
-              B00011110,B11100000,
-              B00011110,B11100000,
-              B00111110,B11110000,
-              B00111110,B11110000,
-              B00111111,B11110000,
-              B00001111,B11000000,
-              B00000111,B10000000,
-              B00000011,B00000000
-            };
+        #else
 
-            const unsigned char status_hotend2_a_bmp[] PROGMEM = {
-              B00011111,B11100000,
-              B00111100,B11110000,
-              B00111011,B01110000,
-              B00111111,B01110000,
-              B00011110,B11100000,
-              B00011101,B11100000,
-              B00111011,B11110000,
-              B00111000,B01110000,
-              B00111111,B11110000,
-              B00001111,B11000000,
-              B00000111,B10000000,
-              B00000011,B00000000
-            };
+          const unsigned char status_hotend1_a_bmp[] PROGMEM = {
+            B00011111,B11100000,
+            B00111110,B11110000,
+            B00111100,B11110000,
+            B00111010,B11110000,
+            B00011110,B11100000,
+            B00011110,B11100000,
+            B00111110,B11110000,
+            B00111110,B11110000,
+            B00111111,B11110000,
+            B00001111,B11000000,
+            B00000111,B10000000,
+            B00000011,B00000000
+          };
 
-          #endif
+          const unsigned char status_hotend2_a_bmp[] PROGMEM = {
+            B00011111,B11100000,
+            B00111100,B11110000,
+            B00111011,B01110000,
+            B00111111,B01110000,
+            B00011110,B11100000,
+            B00011101,B11100000,
+            B00111011,B11110000,
+            B00111000,B01110000,
+            B00111111,B11110000,
+            B00001111,B11000000,
+            B00000111,B10000000,
+            B00000011,B00000000
+          };
 
         #endif
 
@@ -573,6 +590,8 @@
 
       #endif
 
+    #else
+      #define STATUS_HEATERS_HEIGHT 20
     #endif
 
   #endif
@@ -1431,6 +1450,10 @@
     "Status heaters bitmap (status_heaters_bmp) dimensions don't match data."
   );
 
+#else // HOTENDS == 0
+
+  //#error "Incomplete status header"
+
 #endif
 
 //
diff --git a/Marlin/src/lcd/dogm/status_screen_DOGM.cpp b/Marlin/src/lcd/dogm/status_screen_DOGM.cpp
index 6fbfba06edfbaeb26bc238f19b47deca1ba86d3d..9477bc72639704fe9b46bf4abbba7a9b865aa19b 100644
--- a/Marlin/src/lcd/dogm/status_screen_DOGM.cpp
+++ b/Marlin/src/lcd/dogm/status_screen_DOGM.cpp
@@ -93,7 +93,10 @@
   #define CHAMBER_ALT() false
 #endif
 
-#define MAX_HOTEND_DRAW _MIN(HOTENDS, ((LCD_PIXEL_WIDTH - (STATUS_LOGO_BYTEWIDTH + STATUS_FAN_BYTEWIDTH) * 8) / (STATUS_HEATERS_XSPACE)))
+#if HOTENDS
+  #define MAX_HOTEND_DRAW _MIN(HOTENDS, ((LCD_PIXEL_WIDTH - (STATUS_LOGO_BYTEWIDTH + STATUS_FAN_BYTEWIDTH) * 8) / (STATUS_HEATERS_XSPACE)))
+#endif
+
 #define STATUS_HEATERS_BOT (STATUS_HEATERS_Y + STATUS_HEATERS_HEIGHT - 1)
 
 #if ENABLED(MARLIN_DEV_MODE)
@@ -127,6 +130,11 @@ FORCE_INLINE void _draw_heater_status(const heater_ind_t heater, const bool blin
     const bool isHeat = IFBED(BED_ALT(), HOTEND_ALT(heater));
   #endif
 
+  #ifndef STATUS_HOTEND_TEXT_X
+    #define STATUS_HOTEND_TEXT_X(N) 0
+    #define STATUS_HEATERS_Y 0
+  #endif
+
   const uint8_t tx = IFBED(STATUS_BED_TEXT_X, STATUS_HOTEND_TEXT_X(heater));
 
   #if ENABLED(MARLIN_DEV_MODE)
@@ -424,8 +432,10 @@ void MarlinUI::draw_status_screen() {
   //
   if (PAGE_UNDER(6 + 1 + 12 + 1 + 6 + 1)) {
     // Extruders
-    for (uint8_t e = 0; e < MAX_HOTEND_DRAW; ++e)
-      _draw_heater_status((heater_ind_t)e, blink);
+    #if HOTENDS
+      for (uint8_t e = 0; e < MAX_HOTEND_DRAW; ++e)
+        _draw_heater_status((heater_ind_t)e, blink);
+    #endif
 
     // Heated bed
     #if DO_DRAW_BED && DISABLED(STATUS_COMBINE_HEATERS) || (HAS_HEATED_BED && ENABLED(STATUS_COMBINE_HEATERS) && HOTENDS <= 4)
diff --git a/Marlin/src/lcd/extensible_ui/lib/dgus/DGUSDisplay.cpp b/Marlin/src/lcd/extensible_ui/lib/dgus/DGUSDisplay.cpp
index 53c9eeb86dc84726256ff3e900ed6c8c0a06c230..ceac9c9d2784d96eca85d74efd9f74b8ab296194 100644
--- a/Marlin/src/lcd/extensible_ui/lib/dgus/DGUSDisplay.cpp
+++ b/Marlin/src/lcd/extensible_ui/lib/dgus/DGUSDisplay.cpp
@@ -497,21 +497,25 @@ void DGUSScreenVariableHandler::HandleTemperatureChanged(DGUS_VP_Variable &var,
 }
 
 void DGUSScreenVariableHandler::HandleFlowRateChanged(DGUS_VP_Variable &var, void *val_ptr) {
-  uint16_t newvalue = swap16(*(uint16_t*)val_ptr);
-  uint8_t target_extruder;
-  switch (var.VP) {
-    default: return;
-    #if (HOTENDS >= 1)
-      case VP_Flowrate_E1: target_extruder = 0; break;
-    #endif
-    #if (HOTENDS >= 2)
-      case VP_Flowrate_E2: target_extruder = 1; break;
-    #endif
-  }
+  #if EXTRUDERS
+    uint16_t newvalue = swap16(*(uint16_t*)val_ptr);
+    uint8_t target_extruder;
+    switch (var.VP) {
+      default: return;
+      #if (HOTENDS >= 1)
+        case VP_Flowrate_E1: target_extruder = 0; break;
+      #endif
+      #if (HOTENDS >= 2)
+        case VP_Flowrate_E2: target_extruder = 1; break;
+      #endif
+    }
 
-  planner.flow_percentage[target_extruder] = newvalue;
-  planner.refresh_e_factor(target_extruder);
-  ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+    planner.flow_percentage[target_extruder] = newvalue;
+    planner.refresh_e_factor(target_extruder);
+    ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+  #else
+    UNUSED(var); UNUSED(val_ptr);
+  #endif
 }
 
 void DGUSScreenVariableHandler::HandleManualExtrude(DGUS_VP_Variable &var, void *val_ptr) {
diff --git a/Marlin/src/lcd/extensible_ui/ui_api.cpp b/Marlin/src/lcd/extensible_ui/ui_api.cpp
index 43ffca36553f7ab6fb1c369e864af6e3da44cf61..9d29c1f1a0146853c15dd47139d54dd2f491757e 100644
--- a/Marlin/src/lcd/extensible_ui/ui_api.cpp
+++ b/Marlin/src/lcd/extensible_ui/ui_api.cpp
@@ -168,7 +168,7 @@ namespace ExtUI {
   }
 
   void enableHeater(const extruder_t extruder) {
-    #if HEATER_IDLE_HANDLER
+    #if HOTENDS && HEATER_IDLE_HANDLER
       thermalManager.reset_heater_idle_timer(extruder - E0);
     #endif
   }
@@ -184,14 +184,18 @@ namespace ExtUI {
         #if HAS_HEATED_CHAMBER
           case CHAMBER: return; // Chamber has no idle timer
         #endif
-        default: thermalManager.reset_heater_idle_timer(heater - H0);
+        default:
+          #if HOTENDS
+            thermalManager.reset_heater_idle_timer(heater - H0);
+          #endif
+          break;
       }
     #endif
   }
 
   bool isHeaterIdle(const extruder_t extruder) {
     return false
-      #if HEATER_IDLE_HANDLER
+      #if HOTENDS && HEATER_IDLE_HANDLER
         || thermalManager.hotend_idle[extruder - E0].timed_out
       #endif
     ;
@@ -206,7 +210,12 @@ namespace ExtUI {
         #if HAS_HEATED_CHAMBER
           case CHAMBER: return false; // Chamber has no idle timer
         #endif
-        default: return thermalManager.hotend_idle[heater - H0].timed_out;
+        default:
+          #if HOTENDS
+            return thermalManager.hotend_idle[heater - H0].timed_out;
+          #else
+            return false;
+          #endif
       }
     #else
       return false;
@@ -841,22 +850,28 @@ namespace ExtUI {
   }
 
   void setTargetTemp_celsius(float value, const heater_t heater) {
-    constexpr int16_t heater_maxtemp[HOTENDS] = ARRAY_BY_HOTENDS(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP);
-    const int16_t e = heater - H0;
     enableHeater(heater);
     #if HAS_HEATED_BED
       if (heater == BED)
         thermalManager.setTargetBed(clamp(value, 0, BED_MAXTEMP - 10));
       else
     #endif
-        thermalManager.setTargetHotend(clamp(value, 0, heater_maxtemp[e] - 15), e);
+      {
+        #if HOTENDS
+          static constexpr int16_t heater_maxtemp[HOTENDS] = ARRAY_BY_HOTENDS(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP);
+          const int16_t e = heater - H0;
+          thermalManager.setTargetHotend(clamp(value, 0, heater_maxtemp[e] - 15), e);
+        #endif
+      }
   }
 
   void setTargetTemp_celsius(float value, const extruder_t extruder) {
-    constexpr int16_t heater_maxtemp[HOTENDS] = ARRAY_BY_HOTENDS(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP);
-    const int16_t e = extruder - E0;
-    enableHeater(extruder);
-    thermalManager.setTargetHotend(clamp(value, 0, heater_maxtemp[e] - 15), e);
+    #if HOTENDS
+      constexpr int16_t heater_maxtemp[HOTENDS] = ARRAY_BY_HOTENDS(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP);
+      const int16_t e = extruder - E0;
+      enableHeater(extruder);
+      thermalManager.setTargetHotend(clamp(value, 0, heater_maxtemp[e] - 15), e);
+    #endif
   }
 
   void setTargetFan_percent(const float value, const fan_t fan) {
diff --git a/Marlin/src/lcd/menu/menu.h b/Marlin/src/lcd/menu/menu.h
index 77e1e4a749e1874158173f36f4a60e9b206ac6ee..98aa2a2b7995b9ba582c6eafe63ce02d0a471bae 100644
--- a/Marlin/src/lcd/menu/menu.h
+++ b/Marlin/src/lcd/menu/menu.h
@@ -30,7 +30,9 @@
 extern int8_t encoderLine, encoderTopLine, screen_items;
 extern bool screen_changed;
 
-constexpr int16_t heater_maxtemp[HOTENDS] = ARRAY_BY_HOTENDS(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP);
+#if HOTENDS
+  constexpr int16_t heater_maxtemp[HOTENDS] = ARRAY_BY_HOTENDS(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP);
+#endif
 
 void scroll_screen(const uint8_t limit, const bool is_menu);
 bool printer_busy();
diff --git a/Marlin/src/lcd/menu/menu_advanced.cpp b/Marlin/src/lcd/menu/menu_advanced.cpp
index 0d8a562d9aabfe5fde1fbc9034b420c6e5342a4a..9e2746920293dfcd2c443d27358dec52ca5a95ad 100644
--- a/Marlin/src/lcd/menu/menu_advanced.cpp
+++ b/Marlin/src/lcd/menu/menu_advanced.cpp
@@ -43,7 +43,7 @@
   #include "../../module/temperature.h"
 #endif
 
-#ifdef FILAMENT_RUNOUT_DISTANCE_MM
+#if ENABLED(FILAMENT_RUNOUT_SENSOR) && FILAMENT_RUNOUT_DISTANCE_MM
   #include "../../feature/runout.h"
   float lcd_runout_distance_mm;
 #endif
@@ -178,7 +178,7 @@ void menu_backlash();
 
       #if EXTRUDERS == 1
         MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD, &fc_settings[0].unload_length, 0, extrude_maxlength);
-      #else // EXTRUDERS > 1
+      #elif EXTRUDERS > 1
         #define EDIT_FIL_UNLOAD(N) MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E##N, &fc_settings[N-1].unload_length, 0, extrude_maxlength)
         MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD, &fc_settings[active_extruder].unload_length, 0, extrude_maxlength);
         EDIT_FIL_UNLOAD(1);
@@ -199,7 +199,7 @@ void menu_backlash();
 
       #if EXTRUDERS == 1
         MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD, &fc_settings[0].load_length, 0, extrude_maxlength);
-      #else // EXTRUDERS > 1
+      #elif EXTRUDERS > 1
         #define EDIT_FIL_LOAD(N) MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E##N, &fc_settings[N-1].load_length, 0, extrude_maxlength)
         MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD, &fc_settings[active_extruder].load_length, 0, extrude_maxlength);
         EDIT_FIL_LOAD(1);
@@ -219,7 +219,7 @@ void menu_backlash();
       #endif // EXTRUDERS > 1
     #endif
 
-    #ifdef FILAMENT_RUNOUT_DISTANCE_MM
+    #if ENABLED(FILAMENT_RUNOUT_SENSOR) && FILAMENT_RUNOUT_DISTANCE_MM
       MENU_ITEM_EDIT_CALLBACK(float3, MSG_RUNOUT_DISTANCE_MM, &lcd_runout_distance_mm, 1, 30, []{
         runout.set_runout_distance(lcd_runout_distance_mm);
       });
@@ -620,7 +620,7 @@ void menu_backlash();
 #endif // !SLIM_LCD_MENUS
 
 void menu_advanced_settings() {
-  #ifdef FILAMENT_RUNOUT_DISTANCE_MM
+  #if ENABLED(FILAMENT_RUNOUT_SENSOR) && FILAMENT_RUNOUT_DISTANCE_MM
     lcd_runout_distance_mm = runout.runout_distance();
   #endif
   START_MENU();
diff --git a/Marlin/src/lcd/menu/menu_motion.cpp b/Marlin/src/lcd/menu/menu_motion.cpp
index 588500137293ac24636acdff88e156d58d02596c..b0f713079dff27679504efa886730dcad2226632 100644
--- a/Marlin/src/lcd/menu/menu_motion.cpp
+++ b/Marlin/src/lcd/menu/menu_motion.cpp
@@ -158,80 +158,85 @@ static void _lcd_move_xyz(PGM_P name, AxisEnum axis) {
 void lcd_move_x() { _lcd_move_xyz(PSTR(MSG_MOVE_X), X_AXIS); }
 void lcd_move_y() { _lcd_move_xyz(PSTR(MSG_MOVE_Y), Y_AXIS); }
 void lcd_move_z() { _lcd_move_xyz(PSTR(MSG_MOVE_Z), Z_AXIS); }
-static void _lcd_move_e(
-  #if E_MANUAL > 1
-    const int8_t eindex=-1
-  #endif
-) {
-  if (ui.use_click()) return ui.goto_previous_screen_no_defer();
-  if (ui.encoderPosition) {
-    if (!ui.processing_manual_move) {
-      const float diff = float(int16_t(ui.encoderPosition)) * move_menu_scale;
-      #if IS_KINEMATIC
-        manual_move_offset += diff;
+
+#if E_MANUAL
+
+  static void _lcd_move_e(
+    #if E_MANUAL > 1
+      const int8_t eindex=-1
+    #endif
+  ) {
+    if (ui.use_click()) return ui.goto_previous_screen_no_defer();
+    if (ui.encoderPosition) {
+      if (!ui.processing_manual_move) {
+        const float diff = float(int16_t(ui.encoderPosition)) * move_menu_scale;
+        #if IS_KINEMATIC
+          manual_move_offset += diff;
+        #else
+          current_position[E_AXIS] += diff;
+        #endif
+        manual_move_to_current(E_AXIS
+          #if E_MANUAL > 1
+            , eindex
+          #endif
+        );
+        ui.refresh(LCDVIEW_REDRAW_NOW);
+      }
+      ui.encoderPosition = 0;
+    }
+    if (ui.should_draw()) {
+      PGM_P pos_label;
+      #if E_MANUAL == 1
+        pos_label = PSTR(MSG_MOVE_E);
       #else
-        current_position[E_AXIS] += diff;
-      #endif
-      manual_move_to_current(E_AXIS
-        #if E_MANUAL > 1
-          , eindex
+        switch (eindex) {
+          default: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E1); break;
+          case 1: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E2); break;
+          #if E_MANUAL > 2
+            case 2: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E3); break;
+            #if E_MANUAL > 3
+              case 3: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E4); break;
+              #if E_MANUAL > 4
+                case 4: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E5); break;
+                #if E_MANUAL > 5
+                  case 5: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E6); break;
+                #endif // E_MANUAL > 5
+              #endif // E_MANUAL > 4
+            #endif // E_MANUAL > 3
+          #endif // E_MANUAL > 2
+        }
+      #endif // E_MANUAL > 1
+
+      draw_edit_screen(pos_label, ftostr41sign(current_position[E_AXIS]
+        #if IS_KINEMATIC
+          + manual_move_offset
+        #endif
+        #if ENABLED(MANUAL_E_MOVES_RELATIVE)
+          - manual_move_e_origin
         #endif
-      );
-      ui.refresh(LCDVIEW_REDRAW_NOW);
+      ));
     }
-    ui.encoderPosition = 0;
-  }
-  if (ui.should_draw()) {
-    PGM_P pos_label;
-    #if E_MANUAL == 1
-      pos_label = PSTR(MSG_MOVE_E);
-    #else
-      switch (eindex) {
-        default: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E1); break;
-        case 1: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E2); break;
-        #if E_MANUAL > 2
-          case 2: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E3); break;
-          #if E_MANUAL > 3
-            case 3: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E4); break;
-            #if E_MANUAL > 4
-              case 4: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E5); break;
-              #if E_MANUAL > 5
-                case 5: pos_label = PSTR(MSG_MOVE_E MSG_MOVE_E6); break;
-              #endif // E_MANUAL > 5
-            #endif // E_MANUAL > 4
-          #endif // E_MANUAL > 3
-        #endif // E_MANUAL > 2
-      }
-    #endif // E_MANUAL > 1
-
-    draw_edit_screen(pos_label, ftostr41sign(current_position[E_AXIS]
-      #if IS_KINEMATIC
-        + manual_move_offset
-      #endif
-      #if ENABLED(MANUAL_E_MOVES_RELATIVE)
-        - manual_move_e_origin
-      #endif
-    ));
   }
-}
 
-inline void lcd_move_e() { _lcd_move_e(); }
-#if E_MANUAL > 1
-  inline void lcd_move_e0() { _lcd_move_e(0); }
-  inline void lcd_move_e1() { _lcd_move_e(1); }
-  #if E_MANUAL > 2
-    inline void lcd_move_e2() { _lcd_move_e(2); }
-    #if E_MANUAL > 3
-      inline void lcd_move_e3() { _lcd_move_e(3); }
-      #if E_MANUAL > 4
-        inline void lcd_move_e4() { _lcd_move_e(4); }
-        #if E_MANUAL > 5
-          inline void lcd_move_e5() { _lcd_move_e(5); }
-        #endif // E_MANUAL > 5
-      #endif // E_MANUAL > 4
-    #endif // E_MANUAL > 3
-  #endif // E_MANUAL > 2
-#endif // E_MANUAL > 1
+  inline void lcd_move_e() { _lcd_move_e(); }
+  #if E_MANUAL > 1
+    inline void lcd_move_e0() { _lcd_move_e(0); }
+    inline void lcd_move_e1() { _lcd_move_e(1); }
+    #if E_MANUAL > 2
+      inline void lcd_move_e2() { _lcd_move_e(2); }
+      #if E_MANUAL > 3
+        inline void lcd_move_e3() { _lcd_move_e(3); }
+        #if E_MANUAL > 4
+          inline void lcd_move_e4() { _lcd_move_e(4); }
+          #if E_MANUAL > 5
+            inline void lcd_move_e5() { _lcd_move_e(5); }
+          #endif // E_MANUAL > 5
+        #endif // E_MANUAL > 4
+      #endif // E_MANUAL > 3
+    #endif // E_MANUAL > 2
+  #endif // E_MANUAL > 1
+
+#endif // E_MANUAL
 
 //
 // "Motion" > "Move Xmm" > "Move XYZ" submenu
@@ -295,23 +300,26 @@ void _menu_move_distance(const AxisEnum axis, const screenFunc_t func, const int
 void lcd_move_get_x_amount() { _menu_move_distance(X_AXIS, lcd_move_x); }
 void lcd_move_get_y_amount() { _menu_move_distance(Y_AXIS, lcd_move_y); }
 void lcd_move_get_z_amount() { _menu_move_distance(Z_AXIS, lcd_move_z); }
-void lcd_move_get_e_amount() { _menu_move_distance(E_AXIS, lcd_move_e, -1); }
-#if E_MANUAL > 1
-  void lcd_move_get_e0_amount()     { _menu_move_distance(E_AXIS, lcd_move_e0, 0); }
-  void lcd_move_get_e1_amount()     { _menu_move_distance(E_AXIS, lcd_move_e1, 1); }
-  #if E_MANUAL > 2
-    void lcd_move_get_e2_amount()   { _menu_move_distance(E_AXIS, lcd_move_e2, 2); }
-    #if E_MANUAL > 3
-      void lcd_move_get_e3_amount() { _menu_move_distance(E_AXIS, lcd_move_e3, 3); }
-      #if E_MANUAL > 4
-        void lcd_move_get_e4_amount() { _menu_move_distance(E_AXIS, lcd_move_e4, 4); }
-        #if E_MANUAL > 5
-          void lcd_move_get_e5_amount() { _menu_move_distance(E_AXIS, lcd_move_e5, 5); }
-        #endif // E_MANUAL > 5
-      #endif // E_MANUAL > 4
-    #endif // E_MANUAL > 3
-  #endif // E_MANUAL > 2
-#endif // E_MANUAL > 1
+
+#if E_MANUAL
+  void lcd_move_get_e_amount() { _menu_move_distance(E_AXIS, lcd_move_e, -1); }
+  #if E_MANUAL > 1
+    void lcd_move_get_e0_amount()     { _menu_move_distance(E_AXIS, lcd_move_e0, 0); }
+    void lcd_move_get_e1_amount()     { _menu_move_distance(E_AXIS, lcd_move_e1, 1); }
+    #if E_MANUAL > 2
+      void lcd_move_get_e2_amount()   { _menu_move_distance(E_AXIS, lcd_move_e2, 2); }
+      #if E_MANUAL > 3
+        void lcd_move_get_e3_amount() { _menu_move_distance(E_AXIS, lcd_move_e3, 3); }
+        #if E_MANUAL > 4
+          void lcd_move_get_e4_amount() { _menu_move_distance(E_AXIS, lcd_move_e4, 4); }
+          #if E_MANUAL > 5
+            void lcd_move_get_e5_amount() { _menu_move_distance(E_AXIS, lcd_move_e5, 5); }
+          #endif // E_MANUAL > 5
+        #endif // E_MANUAL > 4
+      #endif // E_MANUAL > 3
+    #endif // E_MANUAL > 2
+  #endif // E_MANUAL > 1
+#endif // E_MANUAL
 
 #if ENABLED(DELTA)
   void lcd_lower_z_to_clip_height() {
@@ -396,39 +404,43 @@ void menu_move() {
 
   #endif
 
-  #if EITHER(SWITCHING_EXTRUDER, SWITCHING_NOZZLE)
+  #if E_MANUAL
 
-    // Only the current...
-    MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_get_e_amount);
-    // ...and the non-switching
-    #if E_MANUAL == 5
-      MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E5, lcd_move_get_e4_amount);
-    #elif E_MANUAL == 3
-      MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E3, lcd_move_get_e2_amount);
-    #endif
+    #if EITHER(SWITCHING_EXTRUDER, SWITCHING_NOZZLE)
 
-  #else
-
-    // Independent extruders with one E-stepper per hotend
-    MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_get_e_amount);
-    #if E_MANUAL > 1
-      MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E1, lcd_move_get_e0_amount);
-      MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E2, lcd_move_get_e1_amount);
-      #if E_MANUAL > 2
+      // Only the current...
+      MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_get_e_amount);
+      // ...and the non-switching
+      #if E_MANUAL == 5
+        MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E5, lcd_move_get_e4_amount);
+      #elif E_MANUAL == 3
         MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E3, lcd_move_get_e2_amount);
-        #if E_MANUAL > 3
-          MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E4, lcd_move_get_e3_amount);
-          #if E_MANUAL > 4
-            MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E5, lcd_move_get_e4_amount);
-            #if E_MANUAL > 5
-              MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E6, lcd_move_get_e5_amount);
-            #endif // E_MANUAL > 5
-          #endif // E_MANUAL > 4
-        #endif // E_MANUAL > 3
-      #endif // E_MANUAL > 2
-    #endif // E_MANUAL > 1
+      #endif
 
-  #endif
+    #else
+
+      // Independent extruders with one E-stepper per hotend
+      MENU_ITEM(submenu, MSG_MOVE_E, lcd_move_get_e_amount);
+      #if E_MANUAL > 1
+        MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E1, lcd_move_get_e0_amount);
+        MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E2, lcd_move_get_e1_amount);
+        #if E_MANUAL > 2
+          MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E3, lcd_move_get_e2_amount);
+          #if E_MANUAL > 3
+            MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E4, lcd_move_get_e3_amount);
+            #if E_MANUAL > 4
+              MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E5, lcd_move_get_e4_amount);
+              #if E_MANUAL > 5
+                MENU_ITEM(submenu, MSG_MOVE_E MSG_MOVE_E6, lcd_move_get_e5_amount);
+              #endif // E_MANUAL > 5
+            #endif // E_MANUAL > 4
+          #endif // E_MANUAL > 3
+        #endif // E_MANUAL > 2
+      #endif // E_MANUAL > 1
+
+    #endif
+
+  #endif // E_MANUAL
 
   END_MENU();
 }
diff --git a/Marlin/src/lcd/menu/menu_temperature.cpp b/Marlin/src/lcd/menu/menu_temperature.cpp
index ad987850fdf6caf1224c7e88781e4ee67d54c643..24b88e829c9edf1a4259af395c7ffde41f02dd34 100644
--- a/Marlin/src/lcd/menu/menu_temperature.cpp
+++ b/Marlin/src/lcd/menu/menu_temperature.cpp
@@ -48,7 +48,9 @@ uint8_t MarlinUI::preheat_fan_speed[2];
 //
 
 void _lcd_preheat(const int16_t endnum, const int16_t temph, const int16_t tempb, const uint8_t fan) {
-  if (temph > 0) thermalManager.setTargetHotend(_MIN(heater_maxtemp[endnum] - 15, temph), endnum);
+  #if HOTENDS
+    if (temph > 0) thermalManager.setTargetHotend(_MIN(heater_maxtemp[endnum] - 15, temph), endnum);
+  #endif
   #if HAS_HEATED_BED
     if (tempb >= 0) thermalManager.setTargetBed(tempb);
   #else
@@ -165,12 +167,16 @@ void _lcd_preheat(const int16_t endnum, const int16_t temph, const int16_t tempb
 
 #if HAS_TEMP_HOTEND || HAS_HEATED_BED
 
-  void lcd_preheat_m1_e0_only() { _lcd_preheat(0, ui.preheat_hotend_temp[0], -1, ui.preheat_fan_speed[0]); }
-  void lcd_preheat_m2_e0_only() { _lcd_preheat(0, ui.preheat_hotend_temp[1], -1, ui.preheat_fan_speed[1]); }
+  #if HOTENDS
+    void lcd_preheat_m1_e0_only() { _lcd_preheat(0, ui.preheat_hotend_temp[0], -1, ui.preheat_fan_speed[0]); }
+    void lcd_preheat_m2_e0_only() { _lcd_preheat(0, ui.preheat_hotend_temp[1], -1, ui.preheat_fan_speed[1]); }
+  #endif
 
   #if HAS_HEATED_BED
-    void lcd_preheat_m1_e0() { _lcd_preheat(0, ui.preheat_hotend_temp[0], ui.preheat_bed_temp[0], ui.preheat_fan_speed[0]); }
-    void lcd_preheat_m2_e0() { _lcd_preheat(0, ui.preheat_hotend_temp[1], ui.preheat_bed_temp[1], ui.preheat_fan_speed[1]); }
+    #if HOTENDS
+      void lcd_preheat_m1_e0() { _lcd_preheat(0, ui.preheat_hotend_temp[0], ui.preheat_bed_temp[0], ui.preheat_fan_speed[0]); }
+      void lcd_preheat_m2_e0() { _lcd_preheat(0, ui.preheat_hotend_temp[1], ui.preheat_bed_temp[1], ui.preheat_fan_speed[1]); }
+    #endif
     void lcd_preheat_m1_bedonly() { _lcd_preheat(0, 0, ui.preheat_bed_temp[0], ui.preheat_fan_speed[0]); }
     void lcd_preheat_m2_bedonly() { _lcd_preheat(0, 0, ui.preheat_bed_temp[1], ui.preheat_fan_speed[1]); }
   #endif
@@ -313,7 +319,7 @@ void menu_temperature() {
   //
   #if HOTENDS == 1
     MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE, &thermalManager.temp_hotend[0].target, 0, HEATER_0_MAXTEMP - 15, thermalManager.start_watching_E0);
-  #else // HOTENDS > 1
+  #elif HOTENDS > 1
     #define EDIT_TARGET(N) MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_LCD_N##N, &thermalManager.temp_hotend[N].target, 0, HEATER_##N##_MAXTEMP - 15, thermalManager.start_watching_E##N)
     EDIT_TARGET(0);
     EDIT_TARGET(1);
diff --git a/Marlin/src/lcd/menu/menu_tune.cpp b/Marlin/src/lcd/menu/menu_tune.cpp
index 1c038ea133add0c435709e26bb878800a388dd55..3198e6a1b138385f37c4a74265e4b578e3cad88c 100644
--- a/Marlin/src/lcd/menu/menu_tune.cpp
+++ b/Marlin/src/lcd/menu/menu_tune.cpp
@@ -144,7 +144,7 @@ void menu_tune() {
   //
   #if HOTENDS == 1
     MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE, &thermalManager.temp_hotend[0].target, 0, HEATER_0_MAXTEMP - 15, thermalManager.start_watching_E0);
-  #else // HOTENDS > 1
+  #elif HOTENDS > 1
     #define EDIT_NOZZLE(N) MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(int3, MSG_NOZZLE MSG_LCD_N##N, &thermalManager.temp_hotend[N].target, 0, HEATER_##N##_MAXTEMP - 15, thermalManager.start_watching_E##N)
     EDIT_NOZZLE(0);
     EDIT_NOZZLE(1);
diff --git a/Marlin/src/module/configuration_store.cpp b/Marlin/src/module/configuration_store.cpp
index d122c6e129ea07f6d3b1d396388018ccdaea55e1..5d0a0300ba52e16455e702780bd6c904b020351b 100644
--- a/Marlin/src/module/configuration_store.cpp
+++ b/Marlin/src/module/configuration_store.cpp
@@ -309,7 +309,9 @@ typedef struct SettingsDataStruct {
   //
   // ADVANCED_PAUSE_FEATURE
   //
-  fil_change_settings_t fc_settings[EXTRUDERS];         // M603 T U L
+  #if EXTRUDERS
+    fil_change_settings_t fc_settings[EXTRUDERS];       // M603 T U L
+  #endif
 
   //
   // Tool-change settings
@@ -367,7 +369,7 @@ void MarlinSettings::postprocess() {
 
   #if DISABLED(NO_VOLUMETRICS)
     planner.calculate_volumetric_multipliers();
-  #else
+  #elif EXTRUDERS
     for (uint8_t i = COUNT(planner.e_factor); i--;)
       planner.refresh_e_factor(i);
   #endif
@@ -759,7 +761,7 @@ void MarlinSettings::postprocess() {
     {
       _FIELD_TEST(ui_preheat_hotend_temp);
 
-      #if HAS_LCD_MENU
+      #if HOTENDS && HAS_LCD_MENU
         const int16_t (&ui_preheat_hotend_temp)[2]  = ui.preheat_hotend_temp,
                       (&ui_preheat_bed_temp)[2]     = ui.preheat_bed_temp;
         const uint8_t (&ui_preheat_fan_speed)[2]    = ui.preheat_fan_speed;
@@ -1164,6 +1166,7 @@ void MarlinSettings::postprocess() {
     //
     // Advanced Pause filament load & unload lengths
     //
+    #if EXTRUDERS
     {
       #if DISABLED(ADVANCED_PAUSE_FEATURE)
         const fil_change_settings_t fc_settings[EXTRUDERS] = { 0, 0 };
@@ -1171,6 +1174,7 @@ void MarlinSettings::postprocess() {
       _FIELD_TEST(fc_settings);
       EEPROM_WRITE(fc_settings);
     }
+    #endif
 
     //
     // Multiple Extruders
@@ -1560,7 +1564,7 @@ void MarlinSettings::postprocess() {
       {
         _FIELD_TEST(ui_preheat_hotend_temp);
 
-        #if HAS_LCD_MENU
+        #if HOTENDS && HAS_LCD_MENU
           int16_t (&ui_preheat_hotend_temp)[2]  = ui.preheat_hotend_temp,
                   (&ui_preheat_bed_temp)[2]     = ui.preheat_bed_temp;
           uint8_t (&ui_preheat_fan_speed)[2]    = ui.preheat_fan_speed;
@@ -1968,6 +1972,7 @@ void MarlinSettings::postprocess() {
       //
       // Advanced Pause filament load & unload lengths
       //
+      #if EXTRUDERS
       {
         #if DISABLED(ADVANCED_PAUSE_FEATURE)
           fil_change_settings_t fc_settings[EXTRUDERS];
@@ -1975,6 +1980,7 @@ void MarlinSettings::postprocess() {
         _FIELD_TEST(fc_settings);
         EEPROM_READ(fc_settings);
       }
+      #endif
 
       //
       // Tool-change settings
@@ -2410,7 +2416,7 @@ void MarlinSettings::reset() {
   // Preheat parameters
   //
 
-  #if HAS_LCD_MENU
+  #if HOTENDS && HAS_LCD_MENU
     ui.preheat_hotend_temp[0] = PREHEAT_1_TEMP_HOTEND;
     ui.preheat_hotend_temp[1] = PREHEAT_2_TEMP_HOTEND;
     ui.preheat_bed_temp[0] = PREHEAT_1_TEMP_BED;
@@ -2956,7 +2962,7 @@ void MarlinSettings::reset() {
 
     #endif // [XYZ]_DUAL_ENDSTOPS
 
-    #if HAS_LCD_MENU
+    #if HOTENDS && HAS_LCD_MENU
 
       CONFIG_ECHO_HEADING("Material heatup parameters:");
       for (uint8_t i = 0; i < COUNT(ui.preheat_hotend_temp); i++) {
diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h
index 7c637f9cb8d4dda19cecce7ce3ff796169c698bf..5a8a42d7fc351e78103404e4db127aa6ab706b92 100644
--- a/Marlin/src/module/motion.h
+++ b/Marlin/src/module/motion.h
@@ -124,8 +124,10 @@ XYZ_DEFS(signed char, home_dir, HOME_DIR);
 #if HAS_HOTEND_OFFSET
   extern float hotend_offset[XYZ][HOTENDS];
   void reset_hotend_offsets();
-#else
+#elif HOTENDS > 0
   constexpr float hotend_offset[XYZ][HOTENDS] = { { 0 }, { 0 }, { 0 } };
+#else
+  constexpr float hotend_offset[XYZ][1] = { { 0 }, { 0 }, { 0 } };
 #endif
 
 typedef struct { float min, max; } axis_limits_t;
diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp
index 58934a467b5d83365b203d010efab7b650e9fc45..55e84628614cb6ab4257ff771670cb6e8b02ba08 100644
--- a/Marlin/src/module/planner.cpp
+++ b/Marlin/src/module/planner.cpp
@@ -147,9 +147,10 @@ float Planner::steps_to_mm[XYZE_N];           // (mm) Millimeters per step
   uint8_t Planner::last_extruder = 0;     // Respond to extruder change
 #endif
 
-int16_t Planner::flow_percentage[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(100); // Extrusion factor for each extruder
-
-float Planner::e_factor[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(1.0f); // The flow percentage and volumetric multiplier combine to scale E movement
+#if EXTRUDERS
+  int16_t Planner::flow_percentage[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(100); // Extrusion factor for each extruder
+  float Planner::e_factor[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(1.0f); // The flow percentage and volumetric multiplier combine to scale E movement
+#endif
 
 #if DISABLED(NO_VOLUMETRICS)
   float Planner::filament_size[EXTRUDERS],          // diameter of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder
@@ -1632,7 +1633,11 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
                 db = target[B_AXIS] - position[B_AXIS],
                 dc = target[C_AXIS] - position[C_AXIS];
 
-  int32_t de = target[E_AXIS] - position[E_AXIS];
+  #if EXTRUDERS
+    int32_t de = target[E_AXIS] - position[E_AXIS];
+  #else
+    constexpr int32_t de = 0;
+  #endif
 
   /* <-- add a slash to enable
     SERIAL_ECHOPAIR("  _populate_block FR:", fr_mm_s);
@@ -1642,8 +1647,10 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
     SERIAL_ECHOPAIR(" (", db);
     SERIAL_ECHOPAIR(" steps) C:", target[C_AXIS]);
     SERIAL_ECHOPAIR(" (", dc);
-    SERIAL_ECHOPAIR(" steps) E:", target[E_AXIS]);
-    SERIAL_ECHOPAIR(" (", de);
+    #if EXTRUDERS
+      SERIAL_ECHOPAIR(" steps) E:", target[E_AXIS]);
+      SERIAL_ECHOPAIR(" (", de);
+    #endif
     SERIAL_ECHOLNPGM(" steps)");
   //*/
 
@@ -1712,8 +1719,12 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
   #endif
   if (de < 0) SBI(dm, E_AXIS);
 
-  const float esteps_float = de * e_factor[extruder];
-  const uint32_t esteps = ABS(esteps_float) + 0.5f;
+  #if EXTRUDERS
+    const float esteps_float = de * e_factor[extruder];
+    const uint32_t esteps = ABS(esteps_float) + 0.5f;
+  #else
+    constexpr uint32_t esteps = 0;
+  #endif
 
   // Clear all flags, including the "busy" bit
   block->flag = 0x00;
@@ -1781,10 +1792,17 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
     delta_mm[B_AXIS] = db * steps_to_mm[B_AXIS];
     delta_mm[C_AXIS] = dc * steps_to_mm[C_AXIS];
   #endif
-  delta_mm[E_AXIS] = esteps_float * steps_to_mm[E_AXIS_N(extruder)];
+
+  #if EXTRUDERS
+    delta_mm[E_AXIS] = esteps_float * steps_to_mm[E_AXIS_N(extruder)];
+  #endif
 
   if (block->steps[A_AXIS] < MIN_STEPS_PER_SEGMENT && block->steps[B_AXIS] < MIN_STEPS_PER_SEGMENT && block->steps[C_AXIS] < MIN_STEPS_PER_SEGMENT) {
-    block->millimeters = ABS(delta_mm[E_AXIS]);
+    block->millimeters = (0
+      #if EXTRUDERS
+        + ABS(delta_mm[E_AXIS])
+      #endif
+    );
   }
   else {
     if (millimeters)
@@ -1816,7 +1834,10 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
     #endif
   }
 
-  block->steps[E_AXIS] = esteps;
+  #if EXTRUDERS
+    block->steps[E_AXIS] = esteps;
+  #endif
+
   block->step_event_count = _MAX(block->steps[A_AXIS], block->steps[B_AXIS], block->steps[C_AXIS], esteps);
 
   // Bail if this is a zero-length block
@@ -1874,129 +1895,131 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
   #endif
 
   // Enable extruder(s)
-  if (esteps) {
-    #if ENABLED(AUTO_POWER_CONTROL)
-      powerManager.power_on();
-    #endif
+  #if EXTRUDERS
+    if (esteps) {
+      #if ENABLED(AUTO_POWER_CONTROL)
+        powerManager.power_on();
+      #endif
 
-    #if ENABLED(DISABLE_INACTIVE_EXTRUDER) // Enable only the selected extruder
+      #if ENABLED(DISABLE_INACTIVE_EXTRUDER) // Enable only the selected extruder
 
-      #define DISABLE_IDLE_E(N) if (!g_uc_extruder_last_move[N]) disable_E##N();
+        #define DISABLE_IDLE_E(N) if (!g_uc_extruder_last_move[N]) disable_E##N();
 
-      for (uint8_t i = 0; i < EXTRUDERS; i++)
-        if (g_uc_extruder_last_move[i] > 0) g_uc_extruder_last_move[i]--;
+        for (uint8_t i = 0; i < EXTRUDERS; i++)
+          if (g_uc_extruder_last_move[i] > 0) g_uc_extruder_last_move[i]--;
 
-      switch (extruder) {
-        case 0:
+        switch (extruder) {
+          case 0:
+            #if EXTRUDERS > 1
+              DISABLE_IDLE_E(1);
+              #if EXTRUDERS > 2
+                DISABLE_IDLE_E(2);
+                #if EXTRUDERS > 3
+                  DISABLE_IDLE_E(3);
+                  #if EXTRUDERS > 4
+                    DISABLE_IDLE_E(4);
+                    #if EXTRUDERS > 5
+                      DISABLE_IDLE_E(5);
+                    #endif // EXTRUDERS > 5
+                  #endif // EXTRUDERS > 4
+                #endif // EXTRUDERS > 3
+              #endif // EXTRUDERS > 2
+            #endif // EXTRUDERS > 1
+            enable_E0();
+            g_uc_extruder_last_move[0] = (BLOCK_BUFFER_SIZE) * 2;
+            #if HAS_DUPLICATION_MODE
+              if (extruder_duplication_enabled) {
+                enable_E1();
+                g_uc_extruder_last_move[1] = (BLOCK_BUFFER_SIZE) * 2;
+              }
+            #endif
+          break;
           #if EXTRUDERS > 1
-            DISABLE_IDLE_E(1);
-            #if EXTRUDERS > 2
-              DISABLE_IDLE_E(2);
-              #if EXTRUDERS > 3
-                DISABLE_IDLE_E(3);
-                #if EXTRUDERS > 4
-                  DISABLE_IDLE_E(4);
-                  #if EXTRUDERS > 5
-                    DISABLE_IDLE_E(5);
-                  #endif // EXTRUDERS > 5
-                #endif // EXTRUDERS > 4
-              #endif // EXTRUDERS > 3
-            #endif // EXTRUDERS > 2
-          #endif // EXTRUDERS > 1
-          enable_E0();
-          g_uc_extruder_last_move[0] = (BLOCK_BUFFER_SIZE) * 2;
-          #if HAS_DUPLICATION_MODE
-            if (extruder_duplication_enabled) {
+            case 1:
+              DISABLE_IDLE_E(0);
+              #if EXTRUDERS > 2
+                DISABLE_IDLE_E(2);
+                #if EXTRUDERS > 3
+                  DISABLE_IDLE_E(3);
+                  #if EXTRUDERS > 4
+                    DISABLE_IDLE_E(4);
+                    #if EXTRUDERS > 5
+                      DISABLE_IDLE_E(5);
+                    #endif // EXTRUDERS > 5
+                  #endif // EXTRUDERS > 4
+                #endif // EXTRUDERS > 3
+              #endif // EXTRUDERS > 2
               enable_E1();
               g_uc_extruder_last_move[1] = (BLOCK_BUFFER_SIZE) * 2;
-            }
-          #endif
-        break;
-        #if EXTRUDERS > 1
-          case 1:
-            DISABLE_IDLE_E(0);
-            #if EXTRUDERS > 2
-              DISABLE_IDLE_E(2);
-              #if EXTRUDERS > 3
-                DISABLE_IDLE_E(3);
-                #if EXTRUDERS > 4
-                  DISABLE_IDLE_E(4);
-                  #if EXTRUDERS > 5
-                    DISABLE_IDLE_E(5);
-                  #endif // EXTRUDERS > 5
-                #endif // EXTRUDERS > 4
-              #endif // EXTRUDERS > 3
-            #endif // EXTRUDERS > 2
-            enable_E1();
-            g_uc_extruder_last_move[1] = (BLOCK_BUFFER_SIZE) * 2;
-          break;
-          #if EXTRUDERS > 2
-            case 2:
-              DISABLE_IDLE_E(0);
-              DISABLE_IDLE_E(1);
-              #if EXTRUDERS > 3
-                DISABLE_IDLE_E(3);
-                #if EXTRUDERS > 4
-                  DISABLE_IDLE_E(4);
-                  #if EXTRUDERS > 5
-                    DISABLE_IDLE_E(5);
-                  #endif
-                #endif
-              #endif
-              enable_E2();
-              g_uc_extruder_last_move[2] = (BLOCK_BUFFER_SIZE) * 2;
             break;
-            #if EXTRUDERS > 3
-              case 3:
+            #if EXTRUDERS > 2
+              case 2:
                 DISABLE_IDLE_E(0);
                 DISABLE_IDLE_E(1);
-                DISABLE_IDLE_E(2);
-                #if EXTRUDERS > 4
-                  DISABLE_IDLE_E(4);
-                  #if EXTRUDERS > 5
-                    DISABLE_IDLE_E(5);
+                #if EXTRUDERS > 3
+                  DISABLE_IDLE_E(3);
+                  #if EXTRUDERS > 4
+                    DISABLE_IDLE_E(4);
+                    #if EXTRUDERS > 5
+                      DISABLE_IDLE_E(5);
+                    #endif
                   #endif
                 #endif
-                enable_E3();
-                g_uc_extruder_last_move[3] = (BLOCK_BUFFER_SIZE) * 2;
+                enable_E2();
+                g_uc_extruder_last_move[2] = (BLOCK_BUFFER_SIZE) * 2;
               break;
-              #if EXTRUDERS > 4
-                case 4:
+              #if EXTRUDERS > 3
+                case 3:
                   DISABLE_IDLE_E(0);
                   DISABLE_IDLE_E(1);
                   DISABLE_IDLE_E(2);
-                  DISABLE_IDLE_E(3);
-                  #if EXTRUDERS > 5
-                    DISABLE_IDLE_E(5);
+                  #if EXTRUDERS > 4
+                    DISABLE_IDLE_E(4);
+                    #if EXTRUDERS > 5
+                      DISABLE_IDLE_E(5);
+                    #endif
                   #endif
-                  enable_E4();
-                  g_uc_extruder_last_move[4] = (BLOCK_BUFFER_SIZE) * 2;
+                  enable_E3();
+                  g_uc_extruder_last_move[3] = (BLOCK_BUFFER_SIZE) * 2;
                 break;
-                #if EXTRUDERS > 5
-                  case 5:
+                #if EXTRUDERS > 4
+                  case 4:
                     DISABLE_IDLE_E(0);
                     DISABLE_IDLE_E(1);
                     DISABLE_IDLE_E(2);
                     DISABLE_IDLE_E(3);
-                    DISABLE_IDLE_E(4);
-                    enable_E5();
-                    g_uc_extruder_last_move[5] = (BLOCK_BUFFER_SIZE) * 2;
+                    #if EXTRUDERS > 5
+                      DISABLE_IDLE_E(5);
+                    #endif
+                    enable_E4();
+                    g_uc_extruder_last_move[4] = (BLOCK_BUFFER_SIZE) * 2;
                   break;
-                #endif // EXTRUDERS > 5
-              #endif // EXTRUDERS > 4
-            #endif // EXTRUDERS > 3
-          #endif // EXTRUDERS > 2
-        #endif // EXTRUDERS > 1
-      }
-    #else
-      enable_E0();
-      enable_E1();
-      enable_E2();
-      enable_E3();
-      enable_E4();
-      enable_E5();
-    #endif
-  }
+                  #if EXTRUDERS > 5
+                    case 5:
+                      DISABLE_IDLE_E(0);
+                      DISABLE_IDLE_E(1);
+                      DISABLE_IDLE_E(2);
+                      DISABLE_IDLE_E(3);
+                      DISABLE_IDLE_E(4);
+                      enable_E5();
+                      g_uc_extruder_last_move[5] = (BLOCK_BUFFER_SIZE) * 2;
+                    break;
+                  #endif // EXTRUDERS > 5
+                #endif // EXTRUDERS > 4
+              #endif // EXTRUDERS > 3
+            #endif // EXTRUDERS > 2
+          #endif // EXTRUDERS > 1
+        }
+      #else
+        enable_E0();
+        enable_E1();
+        enable_E2();
+        enable_E3();
+        enable_E4();
+        enable_E5();
+      #endif
+    }
+  #endif // EXTRUDERS
 
   if (esteps)
     NOLESS(fr_mm_s, settings.min_feedrate_mm_s);
diff --git a/Marlin/src/module/planner.h b/Marlin/src/module/planner.h
index 77cde6e2bf9e02067e339ad694da73828adea141..2f9d52698b240e7ac8d058c19bdd88ec549395eb 100644
--- a/Marlin/src/module/planner.h
+++ b/Marlin/src/module/planner.h
@@ -226,9 +226,10 @@ class Planner {
       static uint8_t last_extruder;                 // Respond to extruder change
     #endif
 
-    static int16_t flow_percentage[EXTRUDERS];      // Extrusion factor for each extruder
-
-    static float e_factor[EXTRUDERS];               // The flow percentage and volumetric multiplier combine to scale E movement
+    #if EXTRUDERS
+      static int16_t flow_percentage[EXTRUDERS];    // Extrusion factor for each extruder
+      static float e_factor[EXTRUDERS];             // The flow percentage and volumetric multiplier combine to scale E movement
+    #endif
 
     #if DISABLED(NO_VOLUMETRICS)
       static float filament_size[EXTRUDERS],          // diameter of filament (in millimeters), typically around 1.75 or 2.85, 0 disables the volumetric calculations for the extruder
@@ -357,13 +358,15 @@ class Planner {
     static void reset_acceleration_rates();
     static void refresh_positioning();
 
-    FORCE_INLINE static void refresh_e_factor(const uint8_t e) {
-      e_factor[e] = (flow_percentage[e] * 0.01f
-        #if DISABLED(NO_VOLUMETRICS)
-          * volumetric_multiplier[e]
-        #endif
-      );
-    }
+    #if EXTRUDERS
+      FORCE_INLINE static void refresh_e_factor(const uint8_t e) {
+        e_factor[e] = (flow_percentage[e] * 0.01f
+          #if DISABLED(NO_VOLUMETRICS)
+            * volumetric_multiplier[e]
+          #endif
+        );
+      }
+    #endif
 
     // Manage fans, paste pressure, etc.
     static void check_axes_activity();
diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp
index 4cac00371f48cbe454da45b416d3c4cbf5165be0..2f64652879d9b8c8c9c5e2e1c25e3af351559356 100644
--- a/Marlin/src/module/temperature.cpp
+++ b/Marlin/src/module/temperature.cpp
@@ -112,11 +112,9 @@ Temperature thermalManager;
   bool Temperature::adaptive_fan_slowing = true;
 #endif
 
-hotend_info_t Temperature::temp_hotend[HOTENDS
-  #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
-    + 1
-  #endif
-]; // = { 0 }
+#if HOTENDS
+  hotend_info_t Temperature::temp_hotend[HOTEND_TEMPS]; // = { 0 }
+#endif
 
 #if ENABLED(AUTO_POWER_E_FANS)
   uint8_t Temperature::autofan_speed[HOTENDS]; // = { 0 }
@@ -283,15 +281,17 @@ volatile bool Temperature::temp_meas_ready = false;
 
 #define TEMPDIR(N) ((HEATER_##N##_RAW_LO_TEMP) < (HEATER_##N##_RAW_HI_TEMP) ? 1 : -1)
 
-// Init mintemp and maxtemp with extreme values to prevent false errors during startup
-constexpr temp_range_t sensor_heater_0 { HEATER_0_RAW_LO_TEMP, HEATER_0_RAW_HI_TEMP, 0, 16383 },
-                       sensor_heater_1 { HEATER_1_RAW_LO_TEMP, HEATER_1_RAW_HI_TEMP, 0, 16383 },
-                       sensor_heater_2 { HEATER_2_RAW_LO_TEMP, HEATER_2_RAW_HI_TEMP, 0, 16383 },
-                       sensor_heater_3 { HEATER_3_RAW_LO_TEMP, HEATER_3_RAW_HI_TEMP, 0, 16383 },
-                       sensor_heater_4 { HEATER_4_RAW_LO_TEMP, HEATER_4_RAW_HI_TEMP, 0, 16383 },
-                       sensor_heater_5 { HEATER_5_RAW_LO_TEMP, HEATER_5_RAW_HI_TEMP, 0, 16383 };
+#if HOTENDS
+  // Init mintemp and maxtemp with extreme values to prevent false errors during startup
+  constexpr temp_range_t sensor_heater_0 { HEATER_0_RAW_LO_TEMP, HEATER_0_RAW_HI_TEMP, 0, 16383 },
+                         sensor_heater_1 { HEATER_1_RAW_LO_TEMP, HEATER_1_RAW_HI_TEMP, 0, 16383 },
+                         sensor_heater_2 { HEATER_2_RAW_LO_TEMP, HEATER_2_RAW_HI_TEMP, 0, 16383 },
+                         sensor_heater_3 { HEATER_3_RAW_LO_TEMP, HEATER_3_RAW_HI_TEMP, 0, 16383 },
+                         sensor_heater_4 { HEATER_4_RAW_LO_TEMP, HEATER_4_RAW_HI_TEMP, 0, 16383 },
+                         sensor_heater_5 { HEATER_5_RAW_LO_TEMP, HEATER_5_RAW_HI_TEMP, 0, 16383 };
 
-temp_range_t Temperature::temp_range[HOTENDS] = ARRAY_BY_HOTENDS(sensor_heater_0, sensor_heater_1, sensor_heater_2, sensor_heater_3, sensor_heater_4, sensor_heater_5);
+  temp_range_t Temperature::temp_range[HOTENDS] = ARRAY_BY_HOTENDS(sensor_heater_0, sensor_heater_1, sensor_heater_2, sensor_heater_3, sensor_heater_4, sensor_heater_5);
+#endif
 
 #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
   uint8_t Temperature::consecutive_low_temperature_error[HOTENDS] = { 0 };
@@ -627,17 +627,20 @@ temp_range_t Temperature::temp_range[HOTENDS] = ARRAY_BY_HOTENDS(sensor_heater_0
  * Class and Instance Methods
  */
 
-Temperature::Temperature() { }
-
 int16_t Temperature::getHeaterPower(const heater_ind_t heater_id) {
   switch (heater_id) {
-    default: return temp_hotend[heater_id].soft_pwm_amount;
     #if HAS_HEATED_BED
       case H_BED: return temp_bed.soft_pwm_amount;
     #endif
     #if HAS_HEATED_CHAMBER
       case H_CHAMBER: return temp_chamber.soft_pwm_amount;
     #endif
+    default:
+      #if HOTENDS
+        return temp_hotend[heater_id].soft_pwm_amount;
+      #else
+        return 0;
+      #endif
   }
 }
 
@@ -816,114 +819,118 @@ void Temperature::min_temp_error(const heater_ind_t heater) {
   _temp_error(heater, PSTR(MSG_T_MINTEMP), TEMP_ERR_PSTR(MSG_ERR_MINTEMP, heater));
 }
 
-float Temperature::get_pid_output_hotend(const uint8_t e) {
-  #if HOTENDS == 1
-    #define _HOTEND_TEST true
-  #else
-    #define _HOTEND_TEST (e == active_extruder)
-  #endif
-  E_UNUSED();
-  const uint8_t ee = HOTEND_INDEX;
-  float pid_output;
-  #if ENABLED(PIDTEMP)
-    #if DISABLED(PID_OPENLOOP)
-      static hotend_pid_t work_pid[HOTENDS];
-      static float temp_iState[HOTENDS] = { 0 },
-                   temp_dState[HOTENDS] = { 0 };
-      static bool pid_reset[HOTENDS] = { false };
-      const float pid_error = temp_hotend[ee].target - temp_hotend[ee].celsius;
-
-      if (temp_hotend[ee].target == 0
-        || pid_error < -(PID_FUNCTIONAL_RANGE)
-        #if HEATER_IDLE_HANDLER
-          || hotend_idle[ee].timed_out
-        #endif
-      ) {
-        pid_output = 0;
-        pid_reset[ee] = true;
-      }
-      else if (pid_error > PID_FUNCTIONAL_RANGE) {
-        pid_output = BANG_MAX;
-        pid_reset[ee] = true;
-      }
-      else {
-        if (pid_reset[ee]) {
-          temp_iState[ee] = 0.0;
-          work_pid[ee].Kd = 0.0;
-          pid_reset[ee] = false;
+#if HOTENDS
+
+  float Temperature::get_pid_output_hotend(const uint8_t e) {
+    #if HOTENDS == 1
+      #define _HOTEND_TEST true
+    #else
+      #define _HOTEND_TEST (e == active_extruder)
+    #endif
+    E_UNUSED();
+    const uint8_t ee = HOTEND_INDEX;
+    float pid_output;
+    #if ENABLED(PIDTEMP)
+      #if DISABLED(PID_OPENLOOP)
+        static hotend_pid_t work_pid[HOTENDS];
+        static float temp_iState[HOTENDS] = { 0 },
+                     temp_dState[HOTENDS] = { 0 };
+        static bool pid_reset[HOTENDS] = { false };
+        const float pid_error = temp_hotend[ee].target - temp_hotend[ee].celsius;
+
+        if (temp_hotend[ee].target == 0
+          || pid_error < -(PID_FUNCTIONAL_RANGE)
+          #if HEATER_IDLE_HANDLER
+            || hotend_idle[ee].timed_out
+          #endif
+        ) {
+          pid_output = 0;
+          pid_reset[ee] = true;
         }
+        else if (pid_error > PID_FUNCTIONAL_RANGE) {
+          pid_output = BANG_MAX;
+          pid_reset[ee] = true;
+        }
+        else {
+          if (pid_reset[ee]) {
+            temp_iState[ee] = 0.0;
+            work_pid[ee].Kd = 0.0;
+            pid_reset[ee] = false;
+          }
 
-        work_pid[ee].Kd = work_pid[ee].Kd + PID_K2 * (PID_PARAM(Kd, ee) * (temp_dState[ee] - temp_hotend[ee].celsius) - work_pid[ee].Kd);
-        const float max_power_over_i_gain = float(PID_MAX) / PID_PARAM(Ki, ee) - float(MIN_POWER);
-        temp_iState[ee] = constrain(temp_iState[ee] + pid_error, 0, max_power_over_i_gain);
-        work_pid[ee].Kp = PID_PARAM(Kp, ee) * pid_error;
-        work_pid[ee].Ki = PID_PARAM(Ki, ee) * temp_iState[ee];
-
-        pid_output = work_pid[ee].Kp + work_pid[ee].Ki + work_pid[ee].Kd + float(MIN_POWER);
-
-        #if ENABLED(PID_EXTRUSION_SCALING)
-          work_pid[ee].Kc = 0;
-          if (_HOTEND_TEST) {
-            const long e_position = stepper.position(E_AXIS);
-            if (e_position > last_e_position) {
-              lpq[lpq_ptr] = e_position - last_e_position;
-              last_e_position = e_position;
-            }
-            else
-              lpq[lpq_ptr] = 0;
+          work_pid[ee].Kd = work_pid[ee].Kd + PID_K2 * (PID_PARAM(Kd, ee) * (temp_dState[ee] - temp_hotend[ee].celsius) - work_pid[ee].Kd);
+          const float max_power_over_i_gain = float(PID_MAX) / PID_PARAM(Ki, ee) - float(MIN_POWER);
+          temp_iState[ee] = constrain(temp_iState[ee] + pid_error, 0, max_power_over_i_gain);
+          work_pid[ee].Kp = PID_PARAM(Kp, ee) * pid_error;
+          work_pid[ee].Ki = PID_PARAM(Ki, ee) * temp_iState[ee];
+
+          pid_output = work_pid[ee].Kp + work_pid[ee].Ki + work_pid[ee].Kd + float(MIN_POWER);
+
+          #if ENABLED(PID_EXTRUSION_SCALING)
+            work_pid[ee].Kc = 0;
+            if (_HOTEND_TEST) {
+              const long e_position = stepper.position(E_AXIS);
+              if (e_position > last_e_position) {
+                lpq[lpq_ptr] = e_position - last_e_position;
+                last_e_position = e_position;
+              }
+              else
+                lpq[lpq_ptr] = 0;
 
-            if (++lpq_ptr >= lpq_len) lpq_ptr = 0;
-            work_pid[ee].Kc = (lpq[lpq_ptr] * planner.steps_to_mm[E_AXIS]) * PID_PARAM(Kc, ee);
-            pid_output += work_pid[ee].Kc;
-          }
-        #endif // PID_EXTRUSION_SCALING
+              if (++lpq_ptr >= lpq_len) lpq_ptr = 0;
+              work_pid[ee].Kc = (lpq[lpq_ptr] * planner.steps_to_mm[E_AXIS]) * PID_PARAM(Kc, ee);
+              pid_output += work_pid[ee].Kc;
+            }
+          #endif // PID_EXTRUSION_SCALING
 
-        LIMIT(pid_output, 0, PID_MAX);
-      }
-      temp_dState[ee] = temp_hotend[ee].celsius;
+          LIMIT(pid_output, 0, PID_MAX);
+        }
+        temp_dState[ee] = temp_hotend[ee].celsius;
 
-    #else // PID_OPENLOOP
+      #else // PID_OPENLOOP
 
-      const float pid_output = constrain(temp_hotend[ee].target, 0, PID_MAX);
+        const float pid_output = constrain(temp_hotend[ee].target, 0, PID_MAX);
 
-    #endif // PID_OPENLOOP
+      #endif // PID_OPENLOOP
 
-    #if ENABLED(PID_DEBUG)
-      if (e == active_extruder) {
-        SERIAL_ECHO_START();
-        SERIAL_ECHOPAIR(
-          MSG_PID_DEBUG, ee,
-          MSG_PID_DEBUG_INPUT, temp_hotend[ee].celsius,
-          MSG_PID_DEBUG_OUTPUT, pid_output
-        );
-        #if DISABLED(PID_OPENLOOP)
+      #if ENABLED(PID_DEBUG)
+        if (e == active_extruder) {
+          SERIAL_ECHO_START();
           SERIAL_ECHOPAIR(
-            MSG_PID_DEBUG_PTERM, work_pid[ee].Kp,
-            MSG_PID_DEBUG_ITERM, work_pid[ee].Ki,
-            MSG_PID_DEBUG_DTERM, work_pid[ee].Kd
-            #if ENABLED(PID_EXTRUSION_SCALING)
-              , MSG_PID_DEBUG_CTERM, work_pid[ee].Kc
-            #endif
+            MSG_PID_DEBUG, ee,
+            MSG_PID_DEBUG_INPUT, temp_hotend[ee].celsius,
+            MSG_PID_DEBUG_OUTPUT, pid_output
           );
-        #endif
-        SERIAL_EOL();
-      }
-    #endif // PID_DEBUG
+          #if DISABLED(PID_OPENLOOP)
+            SERIAL_ECHOPAIR(
+              MSG_PID_DEBUG_PTERM, work_pid[ee].Kp,
+              MSG_PID_DEBUG_ITERM, work_pid[ee].Ki,
+              MSG_PID_DEBUG_DTERM, work_pid[ee].Kd
+              #if ENABLED(PID_EXTRUSION_SCALING)
+                , MSG_PID_DEBUG_CTERM, work_pid[ee].Kc
+              #endif
+            );
+          #endif
+          SERIAL_EOL();
+        }
+      #endif // PID_DEBUG
 
-  #else // No PID enabled
+    #else // No PID enabled
+
+      #if HEATER_IDLE_HANDLER
+        #define _TIMED_OUT_TEST hotend_idle[ee].timed_out
+      #else
+        #define _TIMED_OUT_TEST false
+      #endif
+      pid_output = (!_TIMED_OUT_TEST && temp_hotend[ee].celsius < temp_hotend[ee].target) ? BANG_MAX : 0;
+      #undef _TIMED_OUT_TEST
 
-    #if HEATER_IDLE_HANDLER
-      #define _TIMED_OUT_TEST hotend_idle[ee].timed_out
-    #else
-      #define _TIMED_OUT_TEST false
     #endif
-    pid_output = (!_TIMED_OUT_TEST && temp_hotend[ee].celsius < temp_hotend[ee].target) ? BANG_MAX : 0;
-    #undef _TIMED_OUT_TEST
 
-  #endif
+    return pid_output;
+  }
 
-  return pid_output;
-}
+#endif // HOTENDS
 
 #if ENABLED(PIDTEMPBED)
 
@@ -1025,44 +1032,46 @@ void Temperature::manage_heater() {
     if (temp_hotend[1].celsius < _MAX(HEATER_1_MINTEMP, HEATER_1_MAX6675_TMIN + .01)) min_temp_error(H_E1);
   #endif
 
-  #if HAS_THERMAL_PROTECTION || DISABLED(PIDTEMPBED) || HAS_AUTO_FAN || HEATER_IDLE_HANDLER
-    millis_t ms = millis();
-  #endif
+  millis_t ms = millis();
 
-  HOTEND_LOOP() {
-    #if ENABLED(THERMAL_PROTECTION_HOTENDS)
-      if (degHotend(e) > temp_range[e].maxtemp)
-        _temp_error((heater_ind_t)e, PSTR(MSG_T_THERMAL_RUNAWAY), TEMP_ERR_PSTR(MSG_THERMAL_RUNAWAY, e));
-    #endif
+  #if HOTENDS
 
-    #if HEATER_IDLE_HANDLER
-      hotend_idle[e].update(ms);
-    #endif
+    HOTEND_LOOP() {
+      #if ENABLED(THERMAL_PROTECTION_HOTENDS)
+        if (degHotend(e) > temp_range[e].maxtemp)
+          _temp_error((heater_ind_t)e, PSTR(MSG_T_THERMAL_RUNAWAY), TEMP_ERR_PSTR(MSG_THERMAL_RUNAWAY, e));
+      #endif
 
-    #if ENABLED(THERMAL_PROTECTION_HOTENDS)
-      // Check for thermal runaway
-      thermal_runaway_protection(tr_state_machine[e], temp_hotend[e].celsius, temp_hotend[e].target, (heater_ind_t)e, THERMAL_PROTECTION_PERIOD, THERMAL_PROTECTION_HYSTERESIS);
-    #endif
+      #if HEATER_IDLE_HANDLER
+        hotend_idle[e].update(ms);
+      #endif
 
-    temp_hotend[e].soft_pwm_amount = (temp_hotend[e].celsius > temp_range[e].mintemp || is_preheating(e)) && temp_hotend[e].celsius < temp_range[e].maxtemp ? (int)get_pid_output_hotend(e) >> 1 : 0;
+      #if ENABLED(THERMAL_PROTECTION_HOTENDS)
+        // Check for thermal runaway
+        thermal_runaway_protection(tr_state_machine[e], temp_hotend[e].celsius, temp_hotend[e].target, (heater_ind_t)e, THERMAL_PROTECTION_PERIOD, THERMAL_PROTECTION_HYSTERESIS);
+      #endif
 
-    #if WATCH_HOTENDS
-      // Make sure temperature is increasing
-      if (watch_hotend[e].next_ms && ELAPSED(ms, watch_hotend[e].next_ms)) { // Time to check this extruder?
-        if (degHotend(e) < watch_hotend[e].target)                             // Failed to increase enough?
-          _temp_error((heater_ind_t)e, PSTR(MSG_T_HEATING_FAILED), TEMP_ERR_PSTR(MSG_HEATING_FAILED_LCD, e));
-        else                                                                 // Start again if the target is still far off
-          start_watching_hotend(e);
-      }
-    #endif
+      temp_hotend[e].soft_pwm_amount = (temp_hotend[e].celsius > temp_range[e].mintemp || is_preheating(e)) && temp_hotend[e].celsius < temp_range[e].maxtemp ? (int)get_pid_output_hotend(e) >> 1 : 0;
 
-    #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
-      // Make sure measured temperatures are close together
-      if (ABS(temp_hotend[0].celsius - redundant_temperature) > MAX_REDUNDANT_TEMP_SENSOR_DIFF)
-        _temp_error(H_E0, PSTR(MSG_REDUNDANCY), PSTR(MSG_ERR_REDUNDANT_TEMP));
-    #endif
+      #if WATCH_HOTENDS
+        // Make sure temperature is increasing
+        if (watch_hotend[e].next_ms && ELAPSED(ms, watch_hotend[e].next_ms)) { // Time to check this extruder?
+          if (degHotend(e) < watch_hotend[e].target)                             // Failed to increase enough?
+            _temp_error((heater_ind_t)e, PSTR(MSG_T_HEATING_FAILED), TEMP_ERR_PSTR(MSG_HEATING_FAILED_LCD, e));
+          else                                                                 // Start again if the target is still far off
+            start_watching_hotend(e);
+        }
+      #endif
 
-  } // HOTEND_LOOP
+      #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
+        // Make sure measured temperatures are close together
+        if (ABS(temp_hotend[0].celsius - redundant_temperature) > MAX_REDUNDANT_TEMP_SENSOR_DIFF)
+          _temp_error(H_E0, PSTR(MSG_REDUNDANCY), PSTR(MSG_ERR_REDUNDANT_TEMP));
+      #endif
+
+    } // HOTEND_LOOP
+
+  #endif // HOTENDS
 
   #if HAS_AUTO_FAN
     if (ELAPSED(ms, next_auto_fan_check_ms)) { // only need to check fan state very infrequently
@@ -1206,6 +1215,8 @@ void Temperature::manage_heater() {
     //temp_bed.soft_pwm_amount = WITHIN(temp_chamber.celsius, CHAMBER_MINTEMP, CHAMBER_MAXTEMP) ? (int)get_pid_output_chamber() >> 1 : 0;
 
   #endif // HAS_HEATED_CHAMBER
+
+  UNUSED(ms);
 }
 
 #define TEMP_AD595(RAW)  ((RAW) * 5.0 * 100.0 / 1024.0 / (OVERSAMPLENR) * (TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET)
@@ -1358,98 +1369,100 @@ void Temperature::manage_heater() {
   }
 #endif
 
-// Derived from RepRap FiveD extruder::getTemperature()
-// For hot end temperature measurement.
-float Temperature::analog_to_celsius_hotend(const int raw, const uint8_t e) {
-  #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
-    if (e > HOTENDS)
-  #else
-    if (e >= HOTENDS)
-  #endif
-    {
-      SERIAL_ERROR_START();
-      SERIAL_ECHO((int)e);
-      SERIAL_ECHOLNPGM(MSG_INVALID_EXTRUDER_NUM);
-      kill();
-      return 0.0;
-    }
+#if HOTENDS
+  // Derived from RepRap FiveD extruder::getTemperature()
+  // For hot end temperature measurement.
+  float Temperature::analog_to_celsius_hotend(const int raw, const uint8_t e) {
+    #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
+      if (e > HOTENDS)
+    #else
+      if (e >= HOTENDS)
+    #endif
+      {
+        SERIAL_ERROR_START();
+        SERIAL_ECHO((int)e);
+        SERIAL_ECHOLNPGM(MSG_INVALID_EXTRUDER_NUM);
+        kill();
+        return 0.0;
+      }
 
-  switch (e) {
-    case 0:
-      #if ENABLED(HEATER_0_USER_THERMISTOR)
-        return user_thermistor_to_deg_c(CTI_HOTEND_0, raw);
-      #elif ENABLED(HEATER_0_USES_MAX6675)
-        return raw * 0.25;
-      #elif ENABLED(HEATER_0_USES_AD595)
-        return TEMP_AD595(raw);
-      #elif ENABLED(HEATER_0_USES_AD8495)
-        return TEMP_AD8495(raw);
-      #else
-        break;
-      #endif
-    case 1:
-      #if ENABLED(HEATER_1_USER_THERMISTOR)
-        return user_thermistor_to_deg_c(CTI_HOTEND_1, raw);
-      #elif ENABLED(HEATER_1_USES_MAX6675)
-        return raw * 0.25;
-      #elif ENABLED(HEATER_1_USES_AD595)
-        return TEMP_AD595(raw);
-      #elif ENABLED(HEATER_1_USES_AD8495)
-        return TEMP_AD8495(raw);
-      #else
-        break;
-      #endif
-    case 2:
-      #if ENABLED(HEATER_2_USER_THERMISTOR)
-        return user_thermistor_to_deg_c(CTI_HOTEND_2, raw);
-      #elif ENABLED(HEATER_2_USES_AD595)
-        return TEMP_AD595(raw);
-      #elif ENABLED(HEATER_2_USES_AD8495)
-        return TEMP_AD8495(raw);
-      #else
-        break;
-      #endif
-    case 3:
-      #if ENABLED(HEATER_3_USER_THERMISTOR)
-        return user_thermistor_to_deg_c(CTI_HOTEND_3, raw);
-      #elif ENABLED(HEATER_3_USES_AD595)
-        return TEMP_AD595(raw);
-      #elif ENABLED(HEATER_3_USES_AD8495)
-        return TEMP_AD8495(raw);
-      #else
-        break;
-      #endif
-    case 4:
-      #if ENABLED(HEATER_4_USER_THERMISTOR)
-        return user_thermistor_to_deg_c(CTI_HOTEND_4, raw);
-      #elif ENABLED(HEATER_4_USES_AD595)
-        return TEMP_AD595(raw);
-      #elif ENABLED(HEATER_4_USES_AD8495)
-        return TEMP_AD8495(raw);
-      #else
-        break;
-      #endif
-    case 5:
-      #if ENABLED(HEATER_5_USER_THERMISTOR)
-        return user_thermistor_to_deg_c(CTI_HOTEND_5, raw);
-      #elif ENABLED(HEATER_5_USES_AD595)
-        return TEMP_AD595(raw);
-      #elif ENABLED(HEATER_5_USES_AD8495)
-        return TEMP_AD8495(raw);
-      #else
-        break;
-      #endif
-    default: break;
-  }
+    switch (e) {
+      case 0:
+        #if ENABLED(HEATER_0_USER_THERMISTOR)
+          return user_thermistor_to_deg_c(CTI_HOTEND_0, raw);
+        #elif ENABLED(HEATER_0_USES_MAX6675)
+          return raw * 0.25;
+        #elif ENABLED(HEATER_0_USES_AD595)
+          return TEMP_AD595(raw);
+        #elif ENABLED(HEATER_0_USES_AD8495)
+          return TEMP_AD8495(raw);
+        #else
+          break;
+        #endif
+      case 1:
+        #if ENABLED(HEATER_1_USER_THERMISTOR)
+          return user_thermistor_to_deg_c(CTI_HOTEND_1, raw);
+        #elif ENABLED(HEATER_1_USES_MAX6675)
+          return raw * 0.25;
+        #elif ENABLED(HEATER_1_USES_AD595)
+          return TEMP_AD595(raw);
+        #elif ENABLED(HEATER_1_USES_AD8495)
+          return TEMP_AD8495(raw);
+        #else
+          break;
+        #endif
+      case 2:
+        #if ENABLED(HEATER_2_USER_THERMISTOR)
+          return user_thermistor_to_deg_c(CTI_HOTEND_2, raw);
+        #elif ENABLED(HEATER_2_USES_AD595)
+          return TEMP_AD595(raw);
+        #elif ENABLED(HEATER_2_USES_AD8495)
+          return TEMP_AD8495(raw);
+        #else
+          break;
+        #endif
+      case 3:
+        #if ENABLED(HEATER_3_USER_THERMISTOR)
+          return user_thermistor_to_deg_c(CTI_HOTEND_3, raw);
+        #elif ENABLED(HEATER_3_USES_AD595)
+          return TEMP_AD595(raw);
+        #elif ENABLED(HEATER_3_USES_AD8495)
+          return TEMP_AD8495(raw);
+        #else
+          break;
+        #endif
+      case 4:
+        #if ENABLED(HEATER_4_USER_THERMISTOR)
+          return user_thermistor_to_deg_c(CTI_HOTEND_4, raw);
+        #elif ENABLED(HEATER_4_USES_AD595)
+          return TEMP_AD595(raw);
+        #elif ENABLED(HEATER_4_USES_AD8495)
+          return TEMP_AD8495(raw);
+        #else
+          break;
+        #endif
+      case 5:
+        #if ENABLED(HEATER_5_USER_THERMISTOR)
+          return user_thermistor_to_deg_c(CTI_HOTEND_5, raw);
+        #elif ENABLED(HEATER_5_USES_AD595)
+          return TEMP_AD595(raw);
+        #elif ENABLED(HEATER_5_USES_AD8495)
+          return TEMP_AD8495(raw);
+        #else
+          break;
+        #endif
+      default: break;
+    }
 
-  #if HOTEND_USES_THERMISTOR
-    // Thermistor with conversion table?
-    const short(*tt)[][2] = (short(*)[][2])(heater_ttbl_map[e]);
-    SCAN_THERMISTOR_TABLE((*tt), heater_ttbllen_map[e]);
-  #endif
+    #if HOTEND_USES_THERMISTOR
+      // Thermistor with conversion table?
+      const short(*tt)[][2] = (short(*)[][2])(heater_ttbl_map[e]);
+      SCAN_THERMISTOR_TABLE((*tt), heater_ttbllen_map[e]);
+    #endif
 
-  return 0;
-}
+    return 0;
+  }
+#endif // HOTENDS
 
 #if HAS_HEATED_BED
   // Derived from RepRap FiveD extruder::getTemperature()
@@ -1500,7 +1513,9 @@ void Temperature::updateTemperaturesFromRawValues() {
   #if ENABLED(HEATER_1_USES_MAX6675)
     temp_hotend[1].raw = READ_MAX6675(1);
   #endif
-  HOTEND_LOOP() temp_hotend[e].celsius = analog_to_celsius_hotend(temp_hotend[e].raw, e);
+  #if HOTENDS
+    HOTEND_LOOP() temp_hotend[e].celsius = analog_to_celsius_hotend(temp_hotend[e].raw, e);
+  #endif
   #if HAS_HEATED_BED
     temp_bed.celsius = analog_to_celsius_bed(temp_bed.raw);
   #endif
@@ -1802,7 +1817,7 @@ void Temperature::init() {
       #endif // HOTENDS > 2
     #endif // HOTENDS > 1
 
-  #endif // HOTENDS > 1
+  #endif // HOTENDS
 
   #if HAS_HEATED_BED
     #ifdef BED_MINTEMP
@@ -1976,7 +1991,9 @@ void Temperature::disable_all_heaters() {
     planner.autotemp_enabled = false;
   #endif
 
-  HOTEND_LOOP() setTargetHotend(0, e);
+  #if HOTENDS
+    HOTEND_LOOP() setTargetHotend(0, e);
+  #endif
 
   #if HAS_HEATED_BED
     setTargetBed(0);
@@ -2238,9 +2255,11 @@ void Temperature::readings_ready() {
     current_raw_filwidth = raw_filwidth_value >> 10;  // Divide to get to 0-16384 range since we used 1/128 IIR filter approach
   #endif
 
-  HOTEND_LOOP() temp_hotend[e].reset();
-  #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
-    temp_hotend[1].reset();
+  #if HOTENDS
+    HOTEND_LOOP() temp_hotend[e].reset();
+    #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
+      temp_hotend[1].reset();
+    #endif
   #endif
 
   #if HAS_HEATED_BED
@@ -2261,55 +2280,59 @@ void Temperature::readings_ready() {
     joystick.z.reset();
   #endif
 
-  static constexpr int8_t temp_dir[] = {
-    #if ENABLED(HEATER_0_USES_MAX6675)
-      0
-    #else
-      TEMPDIR(0)
-    #endif
-    #if HOTENDS > 1
-      #if ENABLED(HEATER_1_USES_MAX6675)
-        , 0
+  #if HOTENDS
+
+    static constexpr int8_t temp_dir[] = {
+      #if ENABLED(HEATER_0_USES_MAX6675)
+        0
       #else
-        , TEMPDIR(1)
+        TEMPDIR(0)
       #endif
-      #if HOTENDS > 2
-        , TEMPDIR(2)
-        #if HOTENDS > 3
-          , TEMPDIR(3)
-          #if HOTENDS > 4
-            , TEMPDIR(4)
-            #if HOTENDS > 5
-              , TEMPDIR(5)
-            #endif // HOTENDS > 5
-          #endif // HOTENDS > 4
-        #endif // HOTENDS > 3
-      #endif // HOTENDS > 2
-    #endif // HOTENDS > 1
-  };
-
-  for (uint8_t e = 0; e < COUNT(temp_dir); e++) {
-    const int8_t tdir = temp_dir[e];
-    if (tdir) {
-      const int16_t rawtemp = temp_hotend[e].raw * tdir; // normal direction, +rawtemp, else -rawtemp
-      const bool heater_on = (temp_hotend[e].target > 0
-        #if ENABLED(PIDTEMP)
-          || temp_hotend[e].soft_pwm_amount > 0
+      #if HOTENDS > 1
+        #if ENABLED(HEATER_1_USES_MAX6675)
+          , 0
+        #else
+          , TEMPDIR(1)
         #endif
-      );
-      if (rawtemp > temp_range[e].raw_max * tdir) max_temp_error((heater_ind_t)e);
-      if (heater_on && rawtemp < temp_range[e].raw_min * tdir && !is_preheating(e)) {
+        #if HOTENDS > 2
+          , TEMPDIR(2)
+          #if HOTENDS > 3
+            , TEMPDIR(3)
+            #if HOTENDS > 4
+              , TEMPDIR(4)
+              #if HOTENDS > 5
+                , TEMPDIR(5)
+              #endif // HOTENDS > 5
+            #endif // HOTENDS > 4
+          #endif // HOTENDS > 3
+        #endif // HOTENDS > 2
+      #endif // HOTENDS > 1
+    };
+
+    for (uint8_t e = 0; e < COUNT(temp_dir); e++) {
+      const int8_t tdir = temp_dir[e];
+      if (tdir) {
+        const int16_t rawtemp = temp_hotend[e].raw * tdir; // normal direction, +rawtemp, else -rawtemp
+        const bool heater_on = (temp_hotend[e].target > 0
+          #if ENABLED(PIDTEMP)
+            || temp_hotend[e].soft_pwm_amount > 0
+          #endif
+        );
+        if (rawtemp > temp_range[e].raw_max * tdir) max_temp_error((heater_ind_t)e);
+        if (heater_on && rawtemp < temp_range[e].raw_min * tdir && !is_preheating(e)) {
+          #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
+            if (++consecutive_low_temperature_error[e] >= MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED)
+          #endif
+              min_temp_error((heater_ind_t)e);
+        }
         #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
-          if (++consecutive_low_temperature_error[e] >= MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED)
+          else
+            consecutive_low_temperature_error[e] = 0;
         #endif
-            min_temp_error((heater_ind_t)e);
       }
-      #ifdef MAX_CONSECUTIVE_LOW_TEMPERATURE_ERROR_ALLOWED
-        else
-          consecutive_low_temperature_error[e] = 0;
-      #endif
     }
-  }
+
+  #endif // HOTENDS
 
   #if HAS_HEATED_BED
     #if TEMPDIR(BED) < 0
@@ -2399,12 +2422,10 @@ void Temperature::isr() {
     static bool ADCKey_pressed = false;
   #endif
 
-  #if ENABLED(SLOW_PWM_HEATERS)
-    static uint8_t slow_pwm_count = 0;
+  #if HOTENDS
+    static SoftPWM soft_pwm_hotend[HOTENDS];
   #endif
 
-  static SoftPWM soft_pwm_hotend[HOTENDS];
-
   #if HAS_HEATED_BED
     static SoftPWM soft_pwm_bed;
   #endif
@@ -2414,40 +2435,46 @@ void Temperature::isr() {
   #endif
 
   #if DISABLED(SLOW_PWM_HEATERS)
-    constexpr uint8_t pwm_mask =
-      #if ENABLED(SOFT_PWM_DITHER)
-        _BV(SOFT_PWM_SCALE) - 1
-      #else
-        0
-      #endif
-    ;
+
+    #if HOTENDS || HAS_HEATED_BED || HAS_HEATED_CHAMBER
+      constexpr uint8_t pwm_mask =
+        #if ENABLED(SOFT_PWM_DITHER)
+          _BV(SOFT_PWM_SCALE) - 1
+        #else
+          0
+        #endif
+      ;
+      #define _PWM_MOD(N,S,T) do{                           \
+        const bool on = S.add(pwm_mask, T.soft_pwm_amount); \
+        WRITE_HEATER_##N(on);                               \
+      }while(0)
+    #endif
 
     /**
      * Standard heater PWM modulation
      */
     if (pwm_count_tmp >= 127) {
       pwm_count_tmp -= 127;
-      #define _PWM_MOD(N,S,T) do{                           \
-        const bool on = S.add(pwm_mask, T.soft_pwm_amount); \
-        WRITE_HEATER_##N(on);                               \
-      }while(0)
-      #define _PWM_MOD_E(N) _PWM_MOD(N,soft_pwm_hotend[N],temp_hotend[N])
-      _PWM_MOD_E(0);
-      #if HOTENDS > 1
-        _PWM_MOD_E(1);
-        #if HOTENDS > 2
-          _PWM_MOD_E(2);
-          #if HOTENDS > 3
-            _PWM_MOD_E(3);
-            #if HOTENDS > 4
-              _PWM_MOD_E(4);
-              #if HOTENDS > 5
-                _PWM_MOD_E(5);
-              #endif // HOTENDS > 5
-            #endif // HOTENDS > 4
-          #endif // HOTENDS > 3
-        #endif // HOTENDS > 2
-      #endif // HOTENDS > 1
+
+      #if HOTENDS
+        #define _PWM_MOD_E(N) _PWM_MOD(N,soft_pwm_hotend[N],temp_hotend[N])
+        _PWM_MOD_E(0);
+        #if HOTENDS > 1
+          _PWM_MOD_E(1);
+          #if HOTENDS > 2
+            _PWM_MOD_E(2);
+            #if HOTENDS > 3
+              _PWM_MOD_E(3);
+              #if HOTENDS > 4
+                _PWM_MOD_E(4);
+                #if HOTENDS > 5
+                  _PWM_MOD_E(5);
+                #endif // HOTENDS > 5
+              #endif // HOTENDS > 4
+            #endif // HOTENDS > 3
+          #endif // HOTENDS > 2
+        #endif // HOTENDS > 1
+      #endif // HOTENDS
 
       #if HAS_HEATED_BED
         _PWM_MOD(BED,soft_pwm_bed,temp_bed);
@@ -2538,6 +2565,8 @@ void Temperature::isr() {
     #define _SLOW_PWM(NR,PWM,SRC) do{ PWM.count = SRC.soft_pwm_amount; _SLOW_SET(NR,PWM,(PWM.count > 0)); }while(0)
     #define _PWM_OFF(NR,PWM) do{ if (PWM.count < slow_pwm_count) _SLOW_SET(NR,PWM,0); }while(0)
 
+    static uint8_t slow_pwm_count = 0;
+
     if (slow_pwm_count == 0) {
 
       #if HOTENDS
@@ -2634,22 +2663,24 @@ void Temperature::isr() {
       slow_pwm_count++;
       slow_pwm_count &= 0x7F;
 
-      soft_pwm_hotend[0].dec();
-      #if HOTENDS > 1
-        soft_pwm_hotend[1].dec();
-        #if HOTENDS > 2
-          soft_pwm_hotend[2].dec();
-          #if HOTENDS > 3
-            soft_pwm_hotend[3].dec();
-            #if HOTENDS > 4
-              soft_pwm_hotend[4].dec();
-              #if HOTENDS > 5
-                soft_pwm_hotend[5].dec();
-              #endif // HOTENDS > 5
-            #endif // HOTENDS > 4
-          #endif // HOTENDS > 3
-        #endif // HOTENDS > 2
-      #endif // HOTENDS > 1
+      #if HOTENDS
+        soft_pwm_hotend[0].dec();
+        #if HOTENDS > 1
+          soft_pwm_hotend[1].dec();
+          #if HOTENDS > 2
+            soft_pwm_hotend[2].dec();
+            #if HOTENDS > 3
+              soft_pwm_hotend[3].dec();
+              #if HOTENDS > 4
+                soft_pwm_hotend[4].dec();
+                #if HOTENDS > 5
+                  soft_pwm_hotend[5].dec();
+                #endif // HOTENDS > 5
+              #endif // HOTENDS > 4
+            #endif // HOTENDS > 3
+          #endif // HOTENDS > 2
+        #endif // HOTENDS > 1
+      #endif // HOTENDS
       #if HAS_HEATED_BED
         soft_pwm_bed.dec();
       #endif
@@ -2940,7 +2971,7 @@ void Temperature::isr() {
 
   #endif // AUTO_REPORT_TEMPERATURES
 
-  #if HAS_DISPLAY
+  #if HOTENDS && HAS_DISPLAY
     void Temperature::set_heating_message(const uint8_t e) {
       const bool heating = isHeatingHotend(e);
       #if HOTENDS > 1
diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h
index 774935e85a830d34947ff0a36fa33a2f834a8cdf..22b1cd6c98f875984463375af05af6bfbeea763b 100644
--- a/Marlin/src/module/temperature.h
+++ b/Marlin/src/module/temperature.h
@@ -270,11 +270,14 @@ class Temperature {
 
     static volatile bool in_temp_isr;
 
-    static hotend_info_t temp_hotend[HOTENDS
+    #if HOTENDS
       #if ENABLED(TEMP_SENSOR_1_AS_REDUNDANT)
-        + 1
+        #define HOTEND_TEMPS (HOTENDS + 1)
+      #else
+        #define HOTEND_TEMPS HOTENDS
       #endif
-    ];
+      static hotend_info_t temp_hotend[HOTEND_TEMPS];
+    #endif
 
     #if HAS_HEATED_BED
       static bed_info_t temp_bed;
@@ -349,7 +352,9 @@ class Temperature {
       static lpq_ptr_t lpq_ptr;
     #endif
 
-    static temp_range_t temp_range[HOTENDS];
+    #if HOTENDS
+      static temp_range_t temp_range[HOTENDS];
+    #endif
 
     #if HAS_HEATED_BED
       #if WATCH_BED
@@ -417,8 +422,6 @@ class Temperature {
      * Instance Methods
      */
 
-    Temperature();
-
     void init();
 
     /**
@@ -456,7 +459,9 @@ class Temperature {
       }
     #endif
 
-    static float analog_to_celsius_hotend(const int raw, const uint8_t e);
+    #if HOTENDS
+      static float analog_to_celsius_hotend(const int raw, const uint8_t e);
+    #endif
 
     #if HAS_HEATED_BED
       static float analog_to_celsius_bed(const int raw);
@@ -577,19 +582,31 @@ class Temperature {
 
     FORCE_INLINE static float degHotend(const uint8_t e) {
       E_UNUSED();
-      return temp_hotend[HOTEND_INDEX].celsius;
+      #if HOTENDS
+        return temp_hotend[HOTEND_INDEX].celsius;
+      #else
+        return 0;
+      #endif
     }
 
     #if ENABLED(SHOW_TEMP_ADC_VALUES)
       FORCE_INLINE static int16_t rawHotendTemp(const uint8_t e) {
         E_UNUSED();
-        return temp_hotend[HOTEND_INDEX].raw;
+        #if HOTENDS
+          return temp_hotend[HOTEND_INDEX].raw;
+        #else
+          return 0;
+        #endif
       }
     #endif
 
     FORCE_INLINE static int16_t degTargetHotend(const uint8_t e) {
       E_UNUSED();
-      return temp_hotend[HOTEND_INDEX].target;
+      #if HOTENDS
+        return temp_hotend[HOTEND_INDEX].target;
+      #else
+        return 0;
+      #endif
     }
 
     #if WATCH_HOTENDS
@@ -598,52 +615,56 @@ class Temperature {
       static inline void start_watching_hotend(const uint8_t e=0) { UNUSED(e); }
     #endif
 
-    #if HAS_LCD_MENU
-      static inline void start_watching_E0() { start_watching_hotend(0); }
-      static inline void start_watching_E1() { start_watching_hotend(1); }
-      static inline void start_watching_E2() { start_watching_hotend(2); }
-      static inline void start_watching_E3() { start_watching_hotend(3); }
-      static inline void start_watching_E4() { start_watching_hotend(4); }
-      static inline void start_watching_E5() { start_watching_hotend(5); }
-    #endif
+    #if HOTENDS
 
-    static void setTargetHotend(const int16_t celsius, const uint8_t e) {
-      E_UNUSED();
-      const uint8_t ee = HOTEND_INDEX;
-      #ifdef MILLISECONDS_PREHEAT_TIME
-        if (celsius == 0)
-          reset_preheat_time(ee);
-        else if (temp_hotend[ee].target == 0)
-          start_preheat_time(ee);
-      #endif
-      #if ENABLED(AUTO_POWER_CONTROL)
-        powerManager.power_on();
-      #endif
-      temp_hotend[ee].target = _MIN(celsius, temp_range[ee].maxtemp - 15);
-      start_watching_hotend(ee);
-    }
+      #if HAS_LCD_MENU
+        static inline void start_watching_E0() { start_watching_hotend(0); }
+        static inline void start_watching_E1() { start_watching_hotend(1); }
+        static inline void start_watching_E2() { start_watching_hotend(2); }
+        static inline void start_watching_E3() { start_watching_hotend(3); }
+        static inline void start_watching_E4() { start_watching_hotend(4); }
+        static inline void start_watching_E5() { start_watching_hotend(5); }
+      #endif
 
-    FORCE_INLINE static bool isHeatingHotend(const uint8_t e) {
-      E_UNUSED();
-      return temp_hotend[HOTEND_INDEX].target > temp_hotend[HOTEND_INDEX].celsius;
-    }
+      static void setTargetHotend(const int16_t celsius, const uint8_t e) {
+        E_UNUSED();
+        const uint8_t ee = HOTEND_INDEX;
+        #ifdef MILLISECONDS_PREHEAT_TIME
+          if (celsius == 0)
+            reset_preheat_time(ee);
+          else if (temp_hotend[ee].target == 0)
+            start_preheat_time(ee);
+        #endif
+        #if ENABLED(AUTO_POWER_CONTROL)
+          powerManager.power_on();
+        #endif
+        temp_hotend[ee].target = _MIN(celsius, temp_range[ee].maxtemp - 15);
+        start_watching_hotend(ee);
+      }
 
-    FORCE_INLINE static bool isCoolingHotend(const uint8_t e) {
-      E_UNUSED();
-      return temp_hotend[HOTEND_INDEX].target < temp_hotend[HOTEND_INDEX].celsius;
-    }
+      FORCE_INLINE static bool isHeatingHotend(const uint8_t e) {
+        E_UNUSED();
+        return temp_hotend[HOTEND_INDEX].target > temp_hotend[HOTEND_INDEX].celsius;
+      }
 
-    #if HAS_TEMP_HOTEND
-      static bool wait_for_hotend(const uint8_t target_extruder, const bool no_wait_for_cooling=true
-        #if G26_CLICK_CAN_CANCEL
-          , const bool click_to_cancel=false
-        #endif
-      );
-    #endif
+      FORCE_INLINE static bool isCoolingHotend(const uint8_t e) {
+        E_UNUSED();
+        return temp_hotend[HOTEND_INDEX].target < temp_hotend[HOTEND_INDEX].celsius;
+      }
 
-    FORCE_INLINE static bool still_heating(const uint8_t e) {
-      return degTargetHotend(e) > TEMP_HYSTERESIS && ABS(degHotend(e) - degTargetHotend(e)) > TEMP_HYSTERESIS;
-    }
+      #if HAS_TEMP_HOTEND
+        static bool wait_for_hotend(const uint8_t target_extruder, const bool no_wait_for_cooling=true
+          #if G26_CLICK_CAN_CANCEL
+            , const bool click_to_cancel=false
+          #endif
+        );
+      #endif
+
+      FORCE_INLINE static bool still_heating(const uint8_t e) {
+        return degTargetHotend(e) > TEMP_HYSTERESIS && ABS(degHotend(e) - degTargetHotend(e)) > TEMP_HYSTERESIS;
+      }
+
+    #endif // HOTENDS
 
     #if HAS_HEATED_BED
 
diff --git a/Marlin/src/module/tool_change.cpp b/Marlin/src/module/tool_change.cpp
index 264dd16700ae5c7534fb3bb9f0afb825275e4b29..1e5af33c982d298996ea669777e2ac3f4aced715 100644
--- a/Marlin/src/module/tool_change.cpp
+++ b/Marlin/src/module/tool_change.cpp
@@ -695,11 +695,13 @@ inline void fast_line_to_current(const AxisEnum fr_axis) {
 
 #endif // ELECTROMAGNETIC_SWITCHING_TOOLHEAD
 
-inline void invalid_extruder_error(const uint8_t e) {
-  SERIAL_ECHO_START();
-  SERIAL_CHAR('T'); SERIAL_ECHO(int(e));
-  SERIAL_CHAR(' '); SERIAL_ECHOLNPGM(MSG_INVALID_EXTRUDER);
-}
+#if EXTRUDERS
+  inline void invalid_extruder_error(const uint8_t e) {
+    SERIAL_ECHO_START();
+    SERIAL_CHAR('T'); SERIAL_ECHO(int(e));
+    SERIAL_CHAR(' '); SERIAL_ECHOLNPGM(MSG_INVALID_EXTRUDER);
+  }
+#endif
 
 #if ENABLED(DUAL_X_CARRIAGE)
 
@@ -788,6 +790,11 @@ void tool_change(const uint8_t new_tool, bool no_move/*=false*/) {
 
     mmu2.tool_change(new_tool);
 
+  #elif EXTRUDERS == 0
+
+    // Nothing to do
+    UNUSED(new_tool); UNUSED(no_move);
+
   #elif EXTRUDERS < 2
 
     UNUSED(no_move);