diff --git a/esphome/components/adc/sensor.py b/esphome/components/adc/sensor.py
index c812e67a68..5443b9875a 100644
--- a/esphome/components/adc/sensor.py
+++ b/esphome/components/adc/sensor.py
@@ -133,6 +133,7 @@ ADCSensor = adc_ns.class_(
 
 CONFIG_SCHEMA = cv.All(
     sensor.sensor_schema(
+        ADCSensor,
         unit_of_measurement=UNIT_VOLT,
         accuracy_decimals=2,
         device_class=DEVICE_CLASS_VOLTAGE,
@@ -140,7 +141,6 @@ CONFIG_SCHEMA = cv.All(
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(ADCSensor),
             cv.Required(CONF_PIN): validate_adc_pin,
             cv.Optional(CONF_RAW, default=False): cv.boolean,
             cv.SplitDefault(CONF_ATTENUATION, esp32="0db"): cv.All(
diff --git a/esphome/components/ads1115/sensor.py b/esphome/components/ads1115/sensor.py
index da33a39041..190e641ca3 100644
--- a/esphome/components/ads1115/sensor.py
+++ b/esphome/components/ads1115/sensor.py
@@ -52,6 +52,7 @@ ADS1115Sensor = ads1115_ns.class_(
 CONF_ADS1115_ID = "ads1115_id"
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        ADS1115Sensor,
         unit_of_measurement=UNIT_VOLT,
         accuracy_decimals=3,
         device_class=DEVICE_CLASS_VOLTAGE,
@@ -59,7 +60,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(ADS1115Sensor),
             cv.GenerateID(CONF_ADS1115_ID): cv.use_id(ADS1115Component),
             cv.Required(CONF_MULTIPLEXER): cv.enum(MUX, upper=True, space="_"),
             cv.Required(CONF_GAIN): validate_gain,
diff --git a/esphome/components/as3935/sensor.py b/esphome/components/as3935/sensor.py
index 271a29e0fc..5a3967ed7e 100644
--- a/esphome/components/as3935/sensor.py
+++ b/esphome/components/as3935/sensor.py
@@ -4,7 +4,6 @@ from esphome.components import sensor
 from esphome.const import (
     CONF_DISTANCE,
     CONF_LIGHTNING_ENERGY,
-    STATE_CLASS_NONE,
     UNIT_KILOMETER,
     ICON_SIGNAL_DISTANCE_VARIANT,
     ICON_FLASH,
@@ -20,12 +19,10 @@ CONFIG_SCHEMA = cv.Schema(
             unit_of_measurement=UNIT_KILOMETER,
             icon=ICON_SIGNAL_DISTANCE_VARIANT,
             accuracy_decimals=1,
-            state_class=STATE_CLASS_NONE,
         ),
         cv.Optional(CONF_LIGHTNING_ENERGY): sensor.sensor_schema(
             icon=ICON_FLASH,
             accuracy_decimals=1,
-            state_class=STATE_CLASS_NONE,
         ),
     }
 ).extend(cv.COMPONENT_SCHEMA)
diff --git a/esphome/components/bh1750/sensor.py b/esphome/components/bh1750/sensor.py
index 156c7bb375..904e716eb8 100644
--- a/esphome/components/bh1750/sensor.py
+++ b/esphome/components/bh1750/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import i2c, sensor
 from esphome.const import (
-    CONF_ID,
     CONF_RESOLUTION,
     DEVICE_CLASS_ILLUMINANCE,
     STATE_CLASS_MEASUREMENT,
@@ -27,6 +26,7 @@ BH1750Sensor = bh1750_ns.class_(
 CONF_MEASUREMENT_TIME = "measurement_time"
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        BH1750Sensor,
         unit_of_measurement=UNIT_LUX,
         accuracy_decimals=1,
         device_class=DEVICE_CLASS_ILLUMINANCE,
@@ -34,7 +34,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(BH1750Sensor),
             cv.Optional(CONF_RESOLUTION, default=0.5): cv.enum(
                 BH1750_RESOLUTIONS, float=True
             ),
@@ -52,9 +51,8 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
     await i2c.register_i2c_device(var, config)
 
     cg.add(var.set_resolution(config[CONF_RESOLUTION]))
diff --git a/esphome/components/binary_sensor_map/sensor.py b/esphome/components/binary_sensor_map/sensor.py
index 946e2f9e62..7ddf0ecf2a 100644
--- a/esphome/components/binary_sensor_map/sensor.py
+++ b/esphome/components/binary_sensor_map/sensor.py
@@ -3,14 +3,12 @@ import esphome.config_validation as cv
 
 from esphome.components import sensor, binary_sensor
 from esphome.const import (
-    CONF_ID,
     CONF_CHANNELS,
     CONF_VALUE,
     CONF_TYPE,
     ICON_CHECK_CIRCLE_OUTLINE,
     CONF_BINARY_SENSOR,
     CONF_GROUP,
-    STATE_CLASS_NONE,
 )
 
 DEPENDENCIES = ["binary_sensor"]
@@ -33,12 +31,11 @@ entry = {
 CONFIG_SCHEMA = cv.typed_schema(
     {
         CONF_GROUP: sensor.sensor_schema(
+            BinarySensorMap,
             icon=ICON_CHECK_CIRCLE_OUTLINE,
             accuracy_decimals=0,
-            state_class=STATE_CLASS_NONE,
         ).extend(
             {
-                cv.GenerateID(): cv.declare_id(BinarySensorMap),
                 cv.Required(CONF_CHANNELS): cv.All(
                     cv.ensure_list(entry), cv.Length(min=1)
                 ),
@@ -50,9 +47,8 @@ CONFIG_SCHEMA = cv.typed_schema(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
 
     constant = SENSOR_MAP_TYPES[config[CONF_TYPE]]
     cg.add(var.set_sensor_type(constant))
diff --git a/esphome/components/bl0940/sensor.py b/esphome/components/bl0940/sensor.py
index ce630b7408..9f516a8691 100644
--- a/esphome/components/bl0940/sensor.py
+++ b/esphome/components/bl0940/sensor.py
@@ -12,9 +12,7 @@ from esphome.const import (
     DEVICE_CLASS_POWER,
     DEVICE_CLASS_VOLTAGE,
     DEVICE_CLASS_TEMPERATURE,
-    ICON_EMPTY,
     STATE_CLASS_MEASUREMENT,
-    STATE_CLASS_NONE,
     UNIT_AMPERE,
     UNIT_CELSIUS,
     UNIT_KILOWATT_HOURS,
@@ -35,38 +33,39 @@ CONFIG_SCHEMA = (
         {
             cv.GenerateID(): cv.declare_id(BL0940),
             cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
-                UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_MEASUREMENT
+                unit_of_measurement=UNIT_VOLT,
+                accuracy_decimals=1,
+                device_class=DEVICE_CLASS_VOLTAGE,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_CURRENT): sensor.sensor_schema(
-                UNIT_AMPERE,
-                ICON_EMPTY,
-                2,
-                DEVICE_CLASS_CURRENT,
-                STATE_CLASS_MEASUREMENT,
+                unit_of_measurement=UNIT_AMPERE,
+                accuracy_decimals=2,
+                device_class=DEVICE_CLASS_CURRENT,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_POWER): sensor.sensor_schema(
-                UNIT_WATT, ICON_EMPTY, 0, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
+                unit_of_measurement=UNIT_WATT,
+                accuracy_decimals=0,
+                device_class=DEVICE_CLASS_POWER,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_ENERGY): sensor.sensor_schema(
-                UNIT_KILOWATT_HOURS,
-                ICON_EMPTY,
-                0,
-                DEVICE_CLASS_ENERGY,
-                STATE_CLASS_NONE,
+                unit_of_measurement=UNIT_KILOWATT_HOURS,
+                accuracy_decimals=0,
+                device_class=DEVICE_CLASS_ENERGY,
             ),
             cv.Optional(CONF_INTERNAL_TEMPERATURE): sensor.sensor_schema(
-                UNIT_CELSIUS,
-                ICON_EMPTY,
-                0,
-                DEVICE_CLASS_TEMPERATURE,
-                STATE_CLASS_NONE,
+                unit_of_measurement=UNIT_CELSIUS,
+                accuracy_decimals=0,
+                device_class=DEVICE_CLASS_TEMPERATURE,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_EXTERNAL_TEMPERATURE): sensor.sensor_schema(
-                UNIT_CELSIUS,
-                ICON_EMPTY,
-                0,
-                DEVICE_CLASS_TEMPERATURE,
-                STATE_CLASS_NONE,
+                unit_of_measurement=UNIT_CELSIUS,
+                accuracy_decimals=0,
+                device_class=DEVICE_CLASS_TEMPERATURE,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
         }
     )
diff --git a/esphome/components/ble_client/sensor/__init__.py b/esphome/components/ble_client/sensor/__init__.py
index 4aa6a92ba5..71cfb03ae0 100644
--- a/esphome/components/ble_client/sensor/__init__.py
+++ b/esphome/components/ble_client/sensor/__init__.py
@@ -2,9 +2,7 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import sensor, ble_client, esp32_ble_tracker
 from esphome.const import (
-    CONF_ID,
     CONF_LAMBDA,
-    STATE_CLASS_NONE,
     CONF_TRIGGER_ID,
     CONF_SERVICE_UUID,
 )
@@ -31,12 +29,11 @@ BLESensorNotifyTrigger = ble_client_ns.class_(
 
 CONFIG_SCHEMA = cv.All(
     sensor.sensor_schema(
+        BLESensor,
         accuracy_decimals=0,
-        state_class=STATE_CLASS_NONE,
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(BLESensor),
             cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
             cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
             cv.Optional(CONF_DESCRIPTOR_UUID): esp32_ble_tracker.bt_uuid,
@@ -57,7 +54,7 @@ CONFIG_SCHEMA = cv.All(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     if len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid16_format):
         cg.add(
             var.set_service_uuid16(esp32_ble_tracker.as_hex(config[CONF_SERVICE_UUID]))
@@ -124,7 +121,6 @@ async def to_code(config):
     await cg.register_component(var, config)
     await ble_client.register_ble_node(var, config)
     cg.add(var.set_enable_notify(config[CONF_NOTIFY]))
-    await sensor.register_sensor(var, config)
     for conf in config.get(CONF_ON_NOTIFY, []):
         trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
         await ble_client.register_ble_node(trigger, config)
diff --git a/esphome/components/ble_rssi/sensor.py b/esphome/components/ble_rssi/sensor.py
index 0c4308b11a..fd2c2e5cb1 100644
--- a/esphome/components/ble_rssi/sensor.py
+++ b/esphome/components/ble_rssi/sensor.py
@@ -4,7 +4,6 @@ from esphome.components import sensor, esp32_ble_tracker
 from esphome.const import (
     CONF_SERVICE_UUID,
     CONF_MAC_ADDRESS,
-    CONF_ID,
     DEVICE_CLASS_SIGNAL_STRENGTH,
     STATE_CLASS_MEASUREMENT,
     UNIT_DECIBEL,
@@ -19,6 +18,7 @@ BLERSSISensor = ble_rssi_ns.class_(
 
 CONFIG_SCHEMA = cv.All(
     sensor.sensor_schema(
+        BLERSSISensor,
         unit_of_measurement=UNIT_DECIBEL,
         accuracy_decimals=0,
         device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
@@ -26,7 +26,6 @@ CONFIG_SCHEMA = cv.All(
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(BLERSSISensor),
             cv.Optional(CONF_MAC_ADDRESS): cv.mac_address,
             cv.Optional(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
         }
@@ -38,10 +37,9 @@ CONFIG_SCHEMA = cv.All(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
     await esp32_ble_tracker.register_ble_device(var, config)
-    await sensor.register_sensor(var, config)
 
     if CONF_MAC_ADDRESS in config:
         cg.add(var.set_address(config[CONF_MAC_ADDRESS].as_hex))
diff --git a/esphome/components/cd74hc4067/sensor.py b/esphome/components/cd74hc4067/sensor.py
index 7c7cf9ccb7..3eee34b85e 100644
--- a/esphome/components/cd74hc4067/sensor.py
+++ b/esphome/components/cd74hc4067/sensor.py
@@ -25,6 +25,7 @@ CONF_CD74HC4067_ID = "cd74hc4067_id"
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        CD74HC4067Sensor,
         unit_of_measurement=UNIT_VOLT,
         accuracy_decimals=3,
         device_class=DEVICE_CLASS_VOLTAGE,
@@ -33,7 +34,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(CD74HC4067Sensor),
             cv.GenerateID(CONF_CD74HC4067_ID): cv.use_id(CD74HC4067Component),
             cv.Required(CONF_NUMBER): cv.int_range(0, 15),
             cv.Required(CONF_SENSOR): cv.use_id(voltage_sampler.VoltageSampler),
@@ -47,8 +47,8 @@ async def to_code(config):
     parent = await cg.get_variable(config[CONF_CD74HC4067_ID])
 
     var = cg.new_Pvariable(config[CONF_ID], parent)
-    await cg.register_component(var, config)
     await sensor.register_sensor(var, config)
+    await cg.register_component(var, config)
     cg.add(var.set_pin(config[CONF_NUMBER]))
 
     sens = await cg.get_variable(config[CONF_SENSOR])
diff --git a/esphome/components/ct_clamp/sensor.py b/esphome/components/ct_clamp/sensor.py
index 049905d0a7..18ea5877d2 100644
--- a/esphome/components/ct_clamp/sensor.py
+++ b/esphome/components/ct_clamp/sensor.py
@@ -3,7 +3,6 @@ import esphome.config_validation as cv
 from esphome.components import sensor, voltage_sampler
 from esphome.const import (
     CONF_SENSOR,
-    CONF_ID,
     DEVICE_CLASS_CURRENT,
     STATE_CLASS_MEASUREMENT,
     UNIT_AMPERE,
@@ -19,6 +18,7 @@ CTClampSensor = ct_clamp_ns.class_("CTClampSensor", sensor.Sensor, cg.PollingCom
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        CTClampSensor,
         unit_of_measurement=UNIT_AMPERE,
         accuracy_decimals=2,
         device_class=DEVICE_CLASS_CURRENT,
@@ -26,7 +26,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(CTClampSensor),
             cv.Required(CONF_SENSOR): cv.use_id(voltage_sampler.VoltageSampler),
             cv.Optional(
                 CONF_SAMPLE_DURATION, default="200ms"
@@ -38,9 +37,8 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
 
     sens = await cg.get_variable(config[CONF_SENSOR])
     cg.add(var.set_source(sens))
diff --git a/esphome/components/dallas/sensor.py b/esphome/components/dallas/sensor.py
index 14ad0efa7b..9288f0a3a6 100644
--- a/esphome/components/dallas/sensor.py
+++ b/esphome/components/dallas/sensor.py
@@ -9,7 +9,6 @@ from esphome.const import (
     DEVICE_CLASS_TEMPERATURE,
     STATE_CLASS_MEASUREMENT,
     UNIT_CELSIUS,
-    CONF_ID,
 )
 from . import DallasComponent, dallas_ns
 
@@ -17,13 +16,13 @@ DallasTemperatureSensor = dallas_ns.class_("DallasTemperatureSensor", sensor.Sen
 
 CONFIG_SCHEMA = cv.All(
     sensor.sensor_schema(
+        DallasTemperatureSensor,
         unit_of_measurement=UNIT_CELSIUS,
         accuracy_decimals=1,
         device_class=DEVICE_CLASS_TEMPERATURE,
         state_class=STATE_CLASS_MEASUREMENT,
     ).extend(
         {
-            cv.GenerateID(): cv.declare_id(DallasTemperatureSensor),
             cv.GenerateID(CONF_DALLAS_ID): cv.use_id(DallasComponent),
             cv.Optional(CONF_ADDRESS): cv.hex_int,
             cv.Optional(CONF_INDEX): cv.positive_int,
@@ -36,7 +35,7 @@ CONFIG_SCHEMA = cv.All(
 
 async def to_code(config):
     hub = await cg.get_variable(config[CONF_DALLAS_ID])
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
 
     if CONF_ADDRESS in config:
         cg.add(var.set_address(config[CONF_ADDRESS]))
@@ -49,4 +48,3 @@ async def to_code(config):
     cg.add(var.set_parent(hub))
 
     cg.add(hub.register_sensor(var))
-    await sensor.register_sensor(var, config)
diff --git a/esphome/components/daly_bms/sensor.py b/esphome/components/daly_bms/sensor.py
index 1d0ee89914..0ba68d3786 100644
--- a/esphome/components/daly_bms/sensor.py
+++ b/esphome/components/daly_bms/sensor.py
@@ -11,14 +11,11 @@ from esphome.const import (
     DEVICE_CLASS_CURRENT,
     DEVICE_CLASS_BATTERY,
     DEVICE_CLASS_TEMPERATURE,
-    DEVICE_CLASS_EMPTY,
     STATE_CLASS_MEASUREMENT,
-    STATE_CLASS_NONE,
     UNIT_VOLT,
     UNIT_AMPERE,
     UNIT_PERCENT,
     UNIT_CELSIUS,
-    UNIT_EMPTY,
     ICON_FLASH,
     ICON_PERCENT,
     ICON_COUNTER,
@@ -70,109 +67,94 @@ CONFIG_SCHEMA = cv.All(
         {
             cv.GenerateID(CONF_BMS_DALY_ID): cv.use_id(DalyBmsComponent),
             cv.Optional(CONF_VOLTAGE): sensor.sensor_schema(
-                UNIT_VOLT,
-                ICON_FLASH,
-                1,
-                DEVICE_CLASS_VOLTAGE,
-                STATE_CLASS_MEASUREMENT,
+                unit_of_measurement=UNIT_VOLT,
+                icon=ICON_FLASH,
+                accuracy_decimals=1,
+                device_class=DEVICE_CLASS_VOLTAGE,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_CURRENT): sensor.sensor_schema(
-                UNIT_AMPERE,
-                ICON_CURRENT_DC,
-                1,
-                DEVICE_CLASS_CURRENT,
-                STATE_CLASS_MEASUREMENT,
+                unit_of_measurement=UNIT_AMPERE,
+                icon=ICON_CURRENT_DC,
+                accuracy_decimals=1,
+                device_class=DEVICE_CLASS_CURRENT,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(
-                UNIT_PERCENT,
-                ICON_PERCENT,
-                1,
-                DEVICE_CLASS_BATTERY,
-                STATE_CLASS_MEASUREMENT,
+                unit_of_measurement=UNIT_PERCENT,
+                icon=ICON_PERCENT,
+                accuracy_decimals=1,
+                device_class=DEVICE_CLASS_BATTERY,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_MAX_CELL_VOLTAGE): sensor.sensor_schema(
-                UNIT_VOLT,
-                ICON_FLASH,
-                2,
-                DEVICE_CLASS_VOLTAGE,
-                STATE_CLASS_MEASUREMENT,
+                unit_of_measurement=UNIT_VOLT,
+                icon=ICON_FLASH,
+                accuracy_decimals=2,
+                device_class=DEVICE_CLASS_VOLTAGE,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_MAX_CELL_VOLTAGE_NUMBER): sensor.sensor_schema(
-                UNIT_EMPTY,
-                ICON_COUNTER,
-                0,
-                DEVICE_CLASS_EMPTY,
-                STATE_CLASS_NONE,
+                icon=ICON_COUNTER,
+                accuracy_decimals=0,
             ),
             cv.Optional(CONF_MIN_CELL_VOLTAGE): sensor.sensor_schema(
-                UNIT_VOLT,
-                ICON_FLASH,
-                2,
-                DEVICE_CLASS_VOLTAGE,
-                STATE_CLASS_MEASUREMENT,
+                unit_of_measurement=UNIT_VOLT,
+                icon=ICON_FLASH,
+                accuracy_decimals=2,
+                device_class=DEVICE_CLASS_VOLTAGE,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_MIN_CELL_VOLTAGE_NUMBER): sensor.sensor_schema(
-                UNIT_EMPTY,
-                ICON_COUNTER,
-                0,
-                DEVICE_CLASS_EMPTY,
-                STATE_CLASS_NONE,
+                icon=ICON_COUNTER,
+                accuracy_decimals=0,
             ),
             cv.Optional(CONF_MAX_TEMPERATURE): sensor.sensor_schema(
-                UNIT_CELSIUS,
-                ICON_THERMOMETER_CHEVRON_UP,
-                0,
-                DEVICE_CLASS_TEMPERATURE,
-                STATE_CLASS_MEASUREMENT,
+                unit_of_measurement=UNIT_CELSIUS,
+                icon=ICON_THERMOMETER_CHEVRON_UP,
+                accuracy_decimals=0,
+                device_class=DEVICE_CLASS_TEMPERATURE,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_MAX_TEMPERATURE_PROBE_NUMBER): sensor.sensor_schema(
-                UNIT_EMPTY,
-                ICON_COUNTER,
-                0,
-                DEVICE_CLASS_EMPTY,
-                STATE_CLASS_NONE,
+                icon=ICON_COUNTER,
+                accuracy_decimals=0,
             ),
             cv.Optional(CONF_MIN_TEMPERATURE): sensor.sensor_schema(
-                UNIT_CELSIUS,
-                ICON_THERMOMETER_CHEVRON_DOWN,
-                0,
-                DEVICE_CLASS_TEMPERATURE,
-                STATE_CLASS_MEASUREMENT,
+                unit_of_measurement=UNIT_CELSIUS,
+                icon=ICON_THERMOMETER_CHEVRON_DOWN,
+                accuracy_decimals=0,
+                device_class=DEVICE_CLASS_TEMPERATURE,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_MIN_TEMPERATURE_PROBE_NUMBER): sensor.sensor_schema(
-                UNIT_EMPTY,
-                ICON_COUNTER,
-                0,
-                DEVICE_CLASS_EMPTY,
-                STATE_CLASS_NONE,
+                icon=ICON_COUNTER,
+                accuracy_decimals=0,
             ),
             cv.Optional(CONF_REMAINING_CAPACITY): sensor.sensor_schema(
-                UNIT_AMPERE_HOUR,
-                ICON_GAUGE,
-                2,
-                DEVICE_CLASS_VOLTAGE,
-                STATE_CLASS_MEASUREMENT,
+                unit_of_measurement=UNIT_AMPERE_HOUR,
+                icon=ICON_GAUGE,
+                accuracy_decimals=2,
+                device_class=DEVICE_CLASS_VOLTAGE,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_CELLS_NUMBER): sensor.sensor_schema(
-                UNIT_EMPTY,
-                ICON_COUNTER,
-                0,
-                DEVICE_CLASS_EMPTY,
-                STATE_CLASS_NONE,
+                icon=ICON_COUNTER,
+                accuracy_decimals=0,
             ),
             cv.Optional(CONF_TEMPERATURE_1): sensor.sensor_schema(
-                UNIT_CELSIUS,
-                ICON_THERMOMETER,
-                0,
-                DEVICE_CLASS_TEMPERATURE,
-                STATE_CLASS_MEASUREMENT,
+                unit_of_measurement=UNIT_CELSIUS,
+                icon=ICON_THERMOMETER,
+                accuracy_decimals=0,
+                device_class=DEVICE_CLASS_TEMPERATURE,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_TEMPERATURE_2): sensor.sensor_schema(
-                UNIT_CELSIUS,
-                ICON_THERMOMETER,
-                0,
-                DEVICE_CLASS_TEMPERATURE,
-                STATE_CLASS_MEASUREMENT,
+                unit_of_measurement=UNIT_CELSIUS,
+                icon=ICON_THERMOMETER,
+                accuracy_decimals=0,
+                device_class=DEVICE_CLASS_TEMPERATURE,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
         }
     ).extend(cv.COMPONENT_SCHEMA)
diff --git a/esphome/components/demo/__init__.py b/esphome/components/demo/__init__.py
index f20a96ebd4..77b1680d26 100644
--- a/esphome/components/demo/__init__.py
+++ b/esphome/components/demo/__init__.py
@@ -337,12 +337,8 @@ CONFIG_SCHEMA = cv.Schema(
                 },
             ],
         ): [
-            sensor.sensor_schema(accuracy_decimals=0)
-            .extend(cv.polling_component_schema("60s"))
-            .extend(
-                {
-                    cv.GenerateID(): cv.declare_id(DemoSensor),
-                }
+            sensor.sensor_schema(DemoSensor, accuracy_decimals=0).extend(
+                cv.polling_component_schema("60s")
             )
         ],
         cv.Optional(
@@ -427,9 +423,8 @@ async def to_code(config):
         cg.add(var.set_type(conf[CONF_TYPE]))
 
     for conf in config[CONF_SENSORS]:
-        var = cg.new_Pvariable(conf[CONF_ID])
+        var = await sensor.new_sensor(conf)
         await cg.register_component(var, conf)
-        await sensor.register_sensor(var, conf)
 
     for conf in config[CONF_SWITCHES]:
         var = cg.new_Pvariable(conf[CONF_ID])
diff --git a/esphome/components/dsmr/sensor.py b/esphome/components/dsmr/sensor.py
index d809d0d105..bb4722655c 100644
--- a/esphome/components/dsmr/sensor.py
+++ b/esphome/components/dsmr/sensor.py
@@ -2,19 +2,16 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import sensor
 from esphome.const import (
+    CONF_ID,
     DEVICE_CLASS_CURRENT,
-    DEVICE_CLASS_EMPTY,
     DEVICE_CLASS_ENERGY,
     DEVICE_CLASS_GAS,
     DEVICE_CLASS_POWER,
     DEVICE_CLASS_VOLTAGE,
-    ICON_EMPTY,
     STATE_CLASS_MEASUREMENT,
-    STATE_CLASS_NONE,
     STATE_CLASS_TOTAL_INCREASING,
     UNIT_AMPERE,
     UNIT_CUBIC_METER,
-    UNIT_EMPTY,
     UNIT_KILOWATT,
     UNIT_KILOWATT_HOURS,
     UNIT_KILOVOLT_AMPS_REACTIVE_HOURS,
@@ -30,202 +27,214 @@ CONFIG_SCHEMA = cv.Schema(
     {
         cv.GenerateID(CONF_DSMR_ID): cv.use_id(Dsmr),
         cv.Optional("energy_delivered_lux"): sensor.sensor_schema(
-            UNIT_KILOWATT_HOURS,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_ENERGY,
-            STATE_CLASS_TOTAL_INCREASING,
+            unit_of_measurement=UNIT_KILOWATT_HOURS,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_ENERGY,
+            state_class=STATE_CLASS_TOTAL_INCREASING,
         ),
         cv.Optional("energy_delivered_tariff1"): sensor.sensor_schema(
-            UNIT_KILOWATT_HOURS,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_ENERGY,
-            STATE_CLASS_TOTAL_INCREASING,
+            unit_of_measurement=UNIT_KILOWATT_HOURS,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_ENERGY,
+            state_class=STATE_CLASS_TOTAL_INCREASING,
         ),
         cv.Optional("energy_delivered_tariff2"): sensor.sensor_schema(
-            UNIT_KILOWATT_HOURS,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_ENERGY,
-            STATE_CLASS_TOTAL_INCREASING,
+            unit_of_measurement=UNIT_KILOWATT_HOURS,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_ENERGY,
+            state_class=STATE_CLASS_TOTAL_INCREASING,
         ),
         cv.Optional("energy_returned_lux"): sensor.sensor_schema(
-            UNIT_KILOWATT_HOURS,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_ENERGY,
-            STATE_CLASS_TOTAL_INCREASING,
+            unit_of_measurement=UNIT_KILOWATT_HOURS,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_ENERGY,
+            state_class=STATE_CLASS_TOTAL_INCREASING,
         ),
         cv.Optional("energy_returned_tariff1"): sensor.sensor_schema(
-            UNIT_KILOWATT_HOURS,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_ENERGY,
-            STATE_CLASS_TOTAL_INCREASING,
+            unit_of_measurement=UNIT_KILOWATT_HOURS,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_ENERGY,
+            state_class=STATE_CLASS_TOTAL_INCREASING,
         ),
         cv.Optional("energy_returned_tariff2"): sensor.sensor_schema(
-            UNIT_KILOWATT_HOURS,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_ENERGY,
-            STATE_CLASS_TOTAL_INCREASING,
+            unit_of_measurement=UNIT_KILOWATT_HOURS,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_ENERGY,
+            state_class=STATE_CLASS_TOTAL_INCREASING,
         ),
         cv.Optional("total_imported_energy"): sensor.sensor_schema(
-            UNIT_KILOVOLT_AMPS_REACTIVE_HOURS,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_EMPTY,
-            STATE_CLASS_NONE,
+            unit_of_measurement=UNIT_KILOVOLT_AMPS_REACTIVE_HOURS,
+            accuracy_decimals=3,
         ),
         cv.Optional("total_exported_energy"): sensor.sensor_schema(
-            UNIT_KILOVOLT_AMPS_REACTIVE_HOURS,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_EMPTY,
-            STATE_CLASS_NONE,
+            unit_of_measurement=UNIT_KILOVOLT_AMPS_REACTIVE_HOURS,
+            accuracy_decimals=3,
         ),
         cv.Optional("power_delivered"): sensor.sensor_schema(
-            UNIT_KILOWATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
+            unit_of_measurement=UNIT_KILOWATT,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_POWER,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("power_returned"): sensor.sensor_schema(
-            UNIT_KILOWATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
+            unit_of_measurement=UNIT_KILOWATT,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_POWER,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("reactive_power_delivered"): sensor.sensor_schema(
-            UNIT_KILOVOLT_AMPS_REACTIVE,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_POWER,
-            STATE_CLASS_MEASUREMENT,
+            unit_of_measurement=UNIT_KILOVOLT_AMPS_REACTIVE,
+            accuracy_decimals=3,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("reactive_power_returned"): sensor.sensor_schema(
-            UNIT_KILOVOLT_AMPS_REACTIVE,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_POWER,
-            STATE_CLASS_MEASUREMENT,
+            unit_of_measurement=UNIT_KILOVOLT_AMPS_REACTIVE,
+            accuracy_decimals=3,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("electricity_threshold"): sensor.sensor_schema(
-            UNIT_EMPTY, ICON_EMPTY, 3, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE
+            accuracy_decimals=3,
         ),
         cv.Optional("electricity_switch_position"): sensor.sensor_schema(
-            UNIT_EMPTY, ICON_EMPTY, 3, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE
+            accuracy_decimals=3,
         ),
         cv.Optional("electricity_failures"): sensor.sensor_schema(
-            UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE
+            accuracy_decimals=0,
         ),
         cv.Optional("electricity_long_failures"): sensor.sensor_schema(
-            UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE
+            accuracy_decimals=0,
         ),
         cv.Optional("electricity_sags_l1"): sensor.sensor_schema(
-            UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE
+            accuracy_decimals=0,
         ),
         cv.Optional("electricity_sags_l2"): sensor.sensor_schema(
-            UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE
+            accuracy_decimals=0,
         ),
         cv.Optional("electricity_sags_l3"): sensor.sensor_schema(
-            UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE
+            accuracy_decimals=0,
         ),
         cv.Optional("electricity_swells_l1"): sensor.sensor_schema(
-            UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE
+            accuracy_decimals=0,
         ),
         cv.Optional("electricity_swells_l2"): sensor.sensor_schema(
-            UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE
+            accuracy_decimals=0,
         ),
         cv.Optional("electricity_swells_l3"): sensor.sensor_schema(
-            UNIT_EMPTY, ICON_EMPTY, 0, DEVICE_CLASS_EMPTY, STATE_CLASS_NONE
+            accuracy_decimals=0,
         ),
         cv.Optional("current_l1"): sensor.sensor_schema(
-            UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT
+            unit_of_measurement=UNIT_AMPERE,
+            accuracy_decimals=1,
+            device_class=DEVICE_CLASS_CURRENT,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("current_l2"): sensor.sensor_schema(
-            UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT
+            unit_of_measurement=UNIT_AMPERE,
+            accuracy_decimals=1,
+            device_class=DEVICE_CLASS_CURRENT,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("current_l3"): sensor.sensor_schema(
-            UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT, STATE_CLASS_MEASUREMENT
+            unit_of_measurement=UNIT_AMPERE,
+            accuracy_decimals=1,
+            device_class=DEVICE_CLASS_CURRENT,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("power_delivered_l1"): sensor.sensor_schema(
-            UNIT_KILOWATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
+            unit_of_measurement=UNIT_KILOWATT,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_CURRENT,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("power_delivered_l2"): sensor.sensor_schema(
-            UNIT_KILOWATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
+            unit_of_measurement=UNIT_KILOWATT,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_CURRENT,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("power_delivered_l3"): sensor.sensor_schema(
-            UNIT_KILOWATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
+            unit_of_measurement=UNIT_KILOWATT,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_CURRENT,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("power_returned_l1"): sensor.sensor_schema(
-            UNIT_KILOWATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
+            unit_of_measurement=UNIT_KILOWATT,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_CURRENT,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("power_returned_l2"): sensor.sensor_schema(
-            UNIT_KILOWATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
+            unit_of_measurement=UNIT_KILOWATT,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_CURRENT,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("power_returned_l3"): sensor.sensor_schema(
-            UNIT_KILOWATT, ICON_EMPTY, 3, DEVICE_CLASS_POWER, STATE_CLASS_MEASUREMENT
+            unit_of_measurement=UNIT_KILOWATT,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_CURRENT,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("reactive_power_delivered_l1"): sensor.sensor_schema(
-            UNIT_KILOVOLT_AMPS_REACTIVE,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_EMPTY,
-            STATE_CLASS_MEASUREMENT,
+            unit_of_measurement=UNIT_KILOVOLT_AMPS_REACTIVE,
+            accuracy_decimals=3,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("reactive_power_delivered_l2"): sensor.sensor_schema(
-            UNIT_KILOVOLT_AMPS_REACTIVE,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_EMPTY,
-            STATE_CLASS_MEASUREMENT,
+            unit_of_measurement=UNIT_KILOVOLT_AMPS_REACTIVE,
+            accuracy_decimals=3,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("reactive_power_delivered_l3"): sensor.sensor_schema(
-            UNIT_KILOVOLT_AMPS_REACTIVE,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_EMPTY,
-            STATE_CLASS_MEASUREMENT,
+            unit_of_measurement=UNIT_KILOVOLT_AMPS_REACTIVE,
+            accuracy_decimals=3,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("reactive_power_returned_l1"): sensor.sensor_schema(
-            UNIT_KILOVOLT_AMPS_REACTIVE,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_EMPTY,
-            STATE_CLASS_MEASUREMENT,
+            unit_of_measurement=UNIT_KILOVOLT_AMPS_REACTIVE,
+            accuracy_decimals=3,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("reactive_power_returned_l2"): sensor.sensor_schema(
-            UNIT_KILOVOLT_AMPS_REACTIVE,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_EMPTY,
-            STATE_CLASS_MEASUREMENT,
+            unit_of_measurement=UNIT_KILOVOLT_AMPS_REACTIVE,
+            accuracy_decimals=3,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("reactive_power_returned_l3"): sensor.sensor_schema(
-            UNIT_KILOVOLT_AMPS_REACTIVE,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_EMPTY,
-            STATE_CLASS_MEASUREMENT,
+            unit_of_measurement=UNIT_KILOVOLT_AMPS_REACTIVE,
+            accuracy_decimals=3,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("voltage_l1"): sensor.sensor_schema(
-            UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_NONE
+            unit_of_measurement=UNIT_VOLT,
+            accuracy_decimals=1,
+            device_class=DEVICE_CLASS_VOLTAGE,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("voltage_l2"): sensor.sensor_schema(
-            UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_NONE
+            unit_of_measurement=UNIT_VOLT,
+            accuracy_decimals=1,
+            device_class=DEVICE_CLASS_VOLTAGE,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("voltage_l3"): sensor.sensor_schema(
-            UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE, STATE_CLASS_NONE
+            unit_of_measurement=UNIT_VOLT,
+            accuracy_decimals=1,
+            device_class=DEVICE_CLASS_VOLTAGE,
+            state_class=STATE_CLASS_MEASUREMENT,
         ),
         cv.Optional("gas_delivered"): sensor.sensor_schema(
-            UNIT_CUBIC_METER,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_GAS,
-            STATE_CLASS_TOTAL_INCREASING,
+            unit_of_measurement=UNIT_CUBIC_METER,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_GAS,
+            state_class=STATE_CLASS_TOTAL_INCREASING,
         ),
         cv.Optional("gas_delivered_be"): sensor.sensor_schema(
-            UNIT_CUBIC_METER,
-            ICON_EMPTY,
-            3,
-            DEVICE_CLASS_GAS,
-            STATE_CLASS_TOTAL_INCREASING,
+            unit_of_measurement=UNIT_CUBIC_METER,
+            accuracy_decimals=3,
+            device_class=DEVICE_CLASS_GAS,
+            state_class=STATE_CLASS_TOTAL_INCREASING,
         ),
     }
 ).extend(cv.COMPONENT_SCHEMA)
@@ -238,10 +247,10 @@ async def to_code(config):
     for key, conf in config.items():
         if not isinstance(conf, dict):
             continue
-        id = conf.get("id")
+        id = conf[CONF_ID]
         if id and id.type == sensor.Sensor:
-            s = await sensor.new_sensor(conf)
-            cg.add(getattr(hub, f"set_{key}")(s))
+            sens = await sensor.new_sensor(conf)
+            cg.add(getattr(hub, f"set_{key}")(sens))
             sensors.append(f"F({key})")
 
     if sensors:
diff --git a/esphome/components/duty_cycle/sensor.py b/esphome/components/duty_cycle/sensor.py
index 6a367328e6..3dcdf7a818 100644
--- a/esphome/components/duty_cycle/sensor.py
+++ b/esphome/components/duty_cycle/sensor.py
@@ -3,7 +3,6 @@ import esphome.config_validation as cv
 from esphome import pins
 from esphome.components import sensor
 from esphome.const import (
-    CONF_ID,
     CONF_PIN,
     STATE_CLASS_MEASUREMENT,
     UNIT_PERCENT,
@@ -17,25 +16,20 @@ DutyCycleSensor = duty_cycle_ns.class_(
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        DutyCycleSensor,
         unit_of_measurement=UNIT_PERCENT,
         icon=ICON_PERCENT,
         accuracy_decimals=1,
         state_class=STATE_CLASS_MEASUREMENT,
     )
-    .extend(
-        {
-            cv.GenerateID(): cv.declare_id(DutyCycleSensor),
-            cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema),
-        }
-    )
+    .extend({cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema)})
     .extend(cv.polling_component_schema("60s"))
 )
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
 
     pin = await cg.gpio_pin_expression(config[CONF_PIN])
     cg.add(var.set_pin(pin))
diff --git a/esphome/components/esp32_hall/sensor.py b/esphome/components/esp32_hall/sensor.py
index a752da2c97..0c94224ef8 100644
--- a/esphome/components/esp32_hall/sensor.py
+++ b/esphome/components/esp32_hall/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import sensor
 from esphome.const import (
-    CONF_ID,
     STATE_CLASS_MEASUREMENT,
     UNIT_MICROTESLA,
     ICON_MAGNET,
@@ -15,23 +14,15 @@ ESP32HallSensor = esp32_hall_ns.class_(
     "ESP32HallSensor", sensor.Sensor, cg.PollingComponent
 )
 
-CONFIG_SCHEMA = (
-    sensor.sensor_schema(
-        unit_of_measurement=UNIT_MICROTESLA,
-        icon=ICON_MAGNET,
-        accuracy_decimals=1,
-        state_class=STATE_CLASS_MEASUREMENT,
-    )
-    .extend(
-        {
-            cv.GenerateID(): cv.declare_id(ESP32HallSensor),
-        }
-    )
-    .extend(cv.polling_component_schema("60s"))
-)
+CONFIG_SCHEMA = sensor.sensor_schema(
+    ESP32HallSensor,
+    unit_of_measurement=UNIT_MICROTESLA,
+    icon=ICON_MAGNET,
+    accuracy_decimals=1,
+    state_class=STATE_CLASS_MEASUREMENT,
+).extend(cv.polling_component_schema("60s"))
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
diff --git a/esphome/components/fingerprint_grow/sensor.py b/esphome/components/fingerprint_grow/sensor.py
index 4ae670743d..ed4e431dcc 100644
--- a/esphome/components/fingerprint_grow/sensor.py
+++ b/esphome/components/fingerprint_grow/sensor.py
@@ -14,7 +14,6 @@ from esphome.const import (
     ICON_DATABASE,
     ICON_FINGERPRINT,
     ICON_SECURITY,
-    STATE_CLASS_NONE,
 )
 from . import CONF_FINGERPRINT_GROW_ID, FingerprintGrowComponent
 
@@ -26,36 +25,30 @@ CONFIG_SCHEMA = cv.Schema(
         cv.Optional(CONF_FINGERPRINT_COUNT): sensor.sensor_schema(
             icon=ICON_FINGERPRINT,
             accuracy_decimals=0,
-            state_class=STATE_CLASS_NONE,
             entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
         ),
         cv.Optional(CONF_STATUS): sensor.sensor_schema(
             accuracy_decimals=0,
-            state_class=STATE_CLASS_NONE,
             entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
         ),
         cv.Optional(CONF_CAPACITY): sensor.sensor_schema(
             icon=ICON_DATABASE,
             accuracy_decimals=0,
-            state_class=STATE_CLASS_NONE,
             entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
         ),
         cv.Optional(CONF_SECURITY_LEVEL): sensor.sensor_schema(
             icon=ICON_SECURITY,
             accuracy_decimals=0,
-            state_class=STATE_CLASS_NONE,
             entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
         ),
         cv.Optional(CONF_LAST_FINGER_ID): sensor.sensor_schema(
             icon=ICON_ACCOUNT,
             accuracy_decimals=0,
-            state_class=STATE_CLASS_NONE,
             entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
         ),
         cv.Optional(CONF_LAST_CONFIDENCE): sensor.sensor_schema(
             icon=ICON_ACCOUNT_CHECK,
             accuracy_decimals=0,
-            state_class=STATE_CLASS_NONE,
             entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
         ),
     }
diff --git a/esphome/components/gps/__init__.py b/esphome/components/gps/__init__.py
index e485373175..d4cf79b49e 100644
--- a/esphome/components/gps/__init__.py
+++ b/esphome/components/gps/__init__.py
@@ -11,7 +11,6 @@ from esphome.const import (
     CONF_ALTITUDE,
     CONF_SATELLITES,
     STATE_CLASS_MEASUREMENT,
-    STATE_CLASS_NONE,
     UNIT_DEGREES,
     UNIT_KILOMETER_PER_HOUR,
     UNIT_METER,
@@ -35,27 +34,22 @@ CONFIG_SCHEMA = cv.All(
             cv.Optional(CONF_LATITUDE): sensor.sensor_schema(
                 unit_of_measurement=UNIT_DEGREES,
                 accuracy_decimals=6,
-                state_class=STATE_CLASS_NONE,
             ),
             cv.Optional(CONF_LONGITUDE): sensor.sensor_schema(
                 unit_of_measurement=UNIT_DEGREES,
                 accuracy_decimals=6,
-                state_class=STATE_CLASS_NONE,
             ),
             cv.Optional(CONF_SPEED): sensor.sensor_schema(
                 unit_of_measurement=UNIT_KILOMETER_PER_HOUR,
                 accuracy_decimals=6,
-                state_class=STATE_CLASS_NONE,
             ),
             cv.Optional(CONF_COURSE): sensor.sensor_schema(
                 unit_of_measurement=UNIT_DEGREES,
                 accuracy_decimals=2,
-                state_class=STATE_CLASS_NONE,
             ),
             cv.Optional(CONF_ALTITUDE): sensor.sensor_schema(
                 unit_of_measurement=UNIT_METER,
                 accuracy_decimals=1,
-                state_class=STATE_CLASS_NONE,
             ),
             cv.Optional(CONF_SATELLITES): sensor.sensor_schema(
                 accuracy_decimals=0,
diff --git a/esphome/components/hmc5883l/sensor.py b/esphome/components/hmc5883l/sensor.py
index 9d8701079e..26e8e2b60c 100644
--- a/esphome/components/hmc5883l/sensor.py
+++ b/esphome/components/hmc5883l/sensor.py
@@ -8,7 +8,6 @@ from esphome.const import (
     CONF_RANGE,
     ICON_MAGNET,
     STATE_CLASS_MEASUREMENT,
-    STATE_CLASS_NONE,
     UNIT_MICROTESLA,
     UNIT_DEGREES,
     ICON_SCREEN_ROTATION,
@@ -88,7 +87,6 @@ heading_schema = sensor.sensor_schema(
     unit_of_measurement=UNIT_DEGREES,
     icon=ICON_SCREEN_ROTATION,
     accuracy_decimals=1,
-    state_class=STATE_CLASS_NONE,
 )
 
 CONFIG_SCHEMA = (
diff --git a/esphome/components/homeassistant/sensor/__init__.py b/esphome/components/homeassistant/sensor/__init__.py
index cf29db8bb8..28fee9f7f6 100644
--- a/esphome/components/homeassistant/sensor/__init__.py
+++ b/esphome/components/homeassistant/sensor/__init__.py
@@ -5,7 +5,6 @@ from esphome.const import (
     CONF_ATTRIBUTE,
     CONF_ENTITY_ID,
     CONF_ID,
-    STATE_CLASS_NONE,
 )
 from .. import homeassistant_ns
 
@@ -15,12 +14,8 @@ HomeassistantSensor = homeassistant_ns.class_(
     "HomeassistantSensor", sensor.Sensor, cg.Component
 )
 
-CONFIG_SCHEMA = sensor.sensor_schema(
-    accuracy_decimals=1,
-    state_class=STATE_CLASS_NONE,
-).extend(
+CONFIG_SCHEMA = sensor.sensor_schema(HomeassistantSensor, accuracy_decimals=1,).extend(
     {
-        cv.GenerateID(): cv.declare_id(HomeassistantSensor),
         cv.Required(CONF_ENTITY_ID): cv.entity_id,
         cv.Optional(CONF_ATTRIBUTE): cv.string,
     }
diff --git a/esphome/components/hrxl_maxsonar_wr/sensor.py b/esphome/components/hrxl_maxsonar_wr/sensor.py
index dd43bd84a7..a78ae574b1 100644
--- a/esphome/components/hrxl_maxsonar_wr/sensor.py
+++ b/esphome/components/hrxl_maxsonar_wr/sensor.py
@@ -1,8 +1,6 @@
 import esphome.codegen as cg
-import esphome.config_validation as cv
 from esphome.components import sensor, uart
 from esphome.const import (
-    CONF_ID,
     STATE_CLASS_MEASUREMENT,
     UNIT_METER,
     ICON_ARROW_EXPAND_VERTICAL,
@@ -16,24 +14,16 @@ HrxlMaxsonarWrComponent = hrxlmaxsonarwr_ns.class_(
     "HrxlMaxsonarWrComponent", sensor.Sensor, cg.Component, uart.UARTDevice
 )
 
-CONFIG_SCHEMA = (
-    sensor.sensor_schema(
-        unit_of_measurement=UNIT_METER,
-        icon=ICON_ARROW_EXPAND_VERTICAL,
-        accuracy_decimals=3,
-        state_class=STATE_CLASS_MEASUREMENT,
-    )
-    .extend(
-        {
-            cv.GenerateID(): cv.declare_id(HrxlMaxsonarWrComponent),
-        }
-    )
-    .extend(uart.UART_DEVICE_SCHEMA)
-)
+CONFIG_SCHEMA = sensor.sensor_schema(
+    HrxlMaxsonarWrComponent,
+    unit_of_measurement=UNIT_METER,
+    icon=ICON_ARROW_EXPAND_VERTICAL,
+    accuracy_decimals=3,
+    state_class=STATE_CLASS_MEASUREMENT,
+).extend(uart.UART_DEVICE_SCHEMA)
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
     await uart.register_uart_device(var, config)
diff --git a/esphome/components/hx711/sensor.py b/esphome/components/hx711/sensor.py
index cd06cc770f..88a0bb85b7 100644
--- a/esphome/components/hx711/sensor.py
+++ b/esphome/components/hx711/sensor.py
@@ -5,7 +5,6 @@ from esphome.components import sensor
 from esphome.const import (
     CONF_CLK_PIN,
     CONF_GAIN,
-    CONF_ID,
     ICON_SCALE,
     STATE_CLASS_MEASUREMENT,
 )
@@ -24,13 +23,13 @@ GAINS = {
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        HX711Sensor,
         icon=ICON_SCALE,
         accuracy_decimals=0,
         state_class=STATE_CLASS_MEASUREMENT,
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(HX711Sensor),
             cv.Required(CONF_DOUT_PIN): pins.gpio_input_pin_schema,
             cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema,
             cv.Optional(CONF_GAIN, default=128): cv.enum(GAINS, int=True),
@@ -41,9 +40,8 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
 
     dout_pin = await cg.gpio_pin_expression(config[CONF_DOUT_PIN])
     cg.add(var.set_dout_pin(dout_pin))
diff --git a/esphome/components/ltr390/sensor.py b/esphome/components/ltr390/sensor.py
index 0e70f7bb1b..0a765dbe3d 100644
--- a/esphome/components/ltr390/sensor.py
+++ b/esphome/components/ltr390/sensor.py
@@ -52,16 +52,28 @@ CONFIG_SCHEMA = cv.All(
         {
             cv.GenerateID(): cv.declare_id(LTR390Component),
             cv.Optional(CONF_LIGHT): sensor.sensor_schema(
-                UNIT_LUX, ICON_BRIGHTNESS_5, 1, DEVICE_CLASS_ILLUMINANCE
+                unit_of_measurement=UNIT_LUX,
+                icon=ICON_BRIGHTNESS_5,
+                accuracy_decimals=1,
+                device_class=DEVICE_CLASS_ILLUMINANCE,
             ),
             cv.Optional(CONF_AMBIENT_LIGHT): sensor.sensor_schema(
-                UNIT_COUNTS, ICON_BRIGHTNESS_5, 1, DEVICE_CLASS_ILLUMINANCE
+                unit_of_measurement=UNIT_COUNTS,
+                icon=ICON_BRIGHTNESS_5,
+                accuracy_decimals=1,
+                device_class=DEVICE_CLASS_ILLUMINANCE,
             ),
             cv.Optional(CONF_UV_INDEX): sensor.sensor_schema(
-                UNIT_UVI, ICON_BRIGHTNESS_5, 5, DEVICE_CLASS_ILLUMINANCE
+                unit_of_measurement=UNIT_UVI,
+                icon=ICON_BRIGHTNESS_5,
+                accuracy_decimals=5,
+                device_class=DEVICE_CLASS_ILLUMINANCE,
             ),
             cv.Optional(CONF_UV): sensor.sensor_schema(
-                UNIT_COUNTS, ICON_BRIGHTNESS_5, 1, DEVICE_CLASS_ILLUMINANCE
+                unit_of_measurement=UNIT_COUNTS,
+                icon=ICON_BRIGHTNESS_5,
+                accuracy_decimals=1,
+                device_class=DEVICE_CLASS_ILLUMINANCE,
             ),
             cv.Optional(CONF_GAIN, default="X3"): cv.enum(GAIN_OPTIONS),
             cv.Optional(CONF_RESOLUTION, default=18): cv.enum(RES_OPTIONS),
diff --git a/esphome/components/max31855/sensor.py b/esphome/components/max31855/sensor.py
index c7732dfbe3..0cdedb5464 100644
--- a/esphome/components/max31855/sensor.py
+++ b/esphome/components/max31855/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import sensor, spi
 from esphome.const import (
-    CONF_ID,
     CONF_REFERENCE_TEMPERATURE,
     DEVICE_CLASS_TEMPERATURE,
     STATE_CLASS_MEASUREMENT,
@@ -16,13 +15,13 @@ MAX31855Sensor = max31855_ns.class_(
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        MAX31855Sensor,
         unit_of_measurement=UNIT_CELSIUS,
         accuracy_decimals=1,
         device_class=DEVICE_CLASS_TEMPERATURE,
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(MAX31855Sensor),
             cv.Optional(CONF_REFERENCE_TEMPERATURE): sensor.sensor_schema(
                 unit_of_measurement=UNIT_CELSIUS,
                 accuracy_decimals=2,
@@ -37,10 +36,9 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
     await spi.register_spi_device(var, config)
-    await sensor.register_sensor(var, config)
     if CONF_REFERENCE_TEMPERATURE in config:
         tc_ref = await sensor.new_sensor(config[CONF_REFERENCE_TEMPERATURE])
         cg.add(var.set_reference_sensor(tc_ref))
diff --git a/esphome/components/max31856/sensor.py b/esphome/components/max31856/sensor.py
index 083d2ac30c..71f1f3bfa5 100644
--- a/esphome/components/max31856/sensor.py
+++ b/esphome/components/max31856/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import sensor, spi
 from esphome.const import (
-    CONF_ID,
     CONF_MAINS_FILTER,
     DEVICE_CLASS_TEMPERATURE,
     STATE_CLASS_MEASUREMENT,
@@ -22,6 +21,7 @@ FILTER = {
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        MAX31856Sensor,
         unit_of_measurement=UNIT_CELSIUS,
         accuracy_decimals=1,
         device_class=DEVICE_CLASS_TEMPERATURE,
@@ -29,7 +29,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(MAX31856Sensor),
             cv.Optional(CONF_MAINS_FILTER, default="60HZ"): cv.enum(
                 FILTER, upper=True, space=""
             ),
@@ -41,8 +40,7 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
     await spi.register_spi_device(var, config)
-    await sensor.register_sensor(var, config)
     cg.add(var.set_filter(config[CONF_MAINS_FILTER]))
diff --git a/esphome/components/max31865/sensor.py b/esphome/components/max31865/sensor.py
index 33d9c42be3..6eb8bd400d 100644
--- a/esphome/components/max31865/sensor.py
+++ b/esphome/components/max31865/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import sensor, spi
 from esphome.const import (
-    CONF_ID,
     CONF_MAINS_FILTER,
     CONF_REFERENCE_RESISTANCE,
     CONF_RTD_NOMINAL_RESISTANCE,
@@ -25,6 +24,7 @@ FILTER = {
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        MAX31865Sensor,
         unit_of_measurement=UNIT_CELSIUS,
         accuracy_decimals=2,
         device_class=DEVICE_CLASS_TEMPERATURE,
@@ -32,7 +32,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(MAX31865Sensor),
             cv.Required(CONF_REFERENCE_RESISTANCE): cv.All(
                 cv.resistance, cv.Range(min=100, max=10000)
             ),
@@ -51,10 +50,9 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
     await spi.register_spi_device(var, config)
-    await sensor.register_sensor(var, config)
     cg.add(var.set_reference_resistance(config[CONF_REFERENCE_RESISTANCE]))
     cg.add(var.set_nominal_resistance(config[CONF_RTD_NOMINAL_RESISTANCE]))
     cg.add(var.set_filter(config[CONF_MAINS_FILTER]))
diff --git a/esphome/components/max6675/sensor.py b/esphome/components/max6675/sensor.py
index dff8360226..23fc86d2c2 100644
--- a/esphome/components/max6675/sensor.py
+++ b/esphome/components/max6675/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import sensor, spi
 from esphome.const import (
-    CONF_ID,
     DEVICE_CLASS_TEMPERATURE,
     STATE_CLASS_MEASUREMENT,
     UNIT_CELSIUS,
@@ -15,23 +14,18 @@ MAX6675Sensor = max6675_ns.class_(
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        MAX6675Sensor,
         unit_of_measurement=UNIT_CELSIUS,
         accuracy_decimals=1,
         device_class=DEVICE_CLASS_TEMPERATURE,
         state_class=STATE_CLASS_MEASUREMENT,
     )
-    .extend(
-        {
-            cv.GenerateID(): cv.declare_id(MAX6675Sensor),
-        }
-    )
     .extend(cv.polling_component_schema("60s"))
     .extend(spi.spi_device_schema())
 )
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
     await spi.register_spi_device(var, config)
-    await sensor.register_sensor(var, config)
diff --git a/esphome/components/mcp9808/sensor.py b/esphome/components/mcp9808/sensor.py
index c7f6226e0b..2d7874fe20 100644
--- a/esphome/components/mcp9808/sensor.py
+++ b/esphome/components/mcp9808/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import i2c, sensor
 from esphome.const import (
-    CONF_ID,
     DEVICE_CLASS_TEMPERATURE,
     STATE_CLASS_MEASUREMENT,
     UNIT_CELSIUS,
@@ -18,23 +17,18 @@ MCP9808Sensor = mcp9808_ns.class_(
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        MCP9808Sensor,
         unit_of_measurement=UNIT_CELSIUS,
         accuracy_decimals=1,
         device_class=DEVICE_CLASS_TEMPERATURE,
         state_class=STATE_CLASS_MEASUREMENT,
     )
-    .extend(
-        {
-            cv.GenerateID(): cv.declare_id(MCP9808Sensor),
-        }
-    )
     .extend(cv.polling_component_schema("60s"))
     .extend(i2c.i2c_device_schema(0x18))
 )
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
     await i2c.register_i2c_device(var, config)
-    await sensor.register_sensor(var, config)
diff --git a/esphome/components/mqtt_subscribe/sensor/__init__.py b/esphome/components/mqtt_subscribe/sensor/__init__.py
index 420d4f152c..6fe0c48ae0 100644
--- a/esphome/components/mqtt_subscribe/sensor/__init__.py
+++ b/esphome/components/mqtt_subscribe/sensor/__init__.py
@@ -2,10 +2,8 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import mqtt, sensor
 from esphome.const import (
-    CONF_ID,
     CONF_QOS,
     CONF_TOPIC,
-    STATE_CLASS_NONE,
 )
 from .. import mqtt_subscribe_ns
 
@@ -18,12 +16,11 @@ MQTTSubscribeSensor = mqtt_subscribe_ns.class_(
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        MQTTSubscribeSensor,
         accuracy_decimals=1,
-        state_class=STATE_CLASS_NONE,
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(MQTTSubscribeSensor),
             cv.GenerateID(CONF_MQTT_PARENT_ID): cv.use_id(mqtt.MQTTClientComponent),
             cv.Required(CONF_TOPIC): cv.subscribe_topic,
             cv.Optional(CONF_QOS, default=0): cv.mqtt_qos,
@@ -34,9 +31,8 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
 
     parent = await cg.get_variable(config[CONF_MQTT_PARENT_ID])
     cg.add(var.set_parent(parent))
diff --git a/esphome/components/nextion/sensor/__init__.py b/esphome/components/nextion/sensor/__init__.py
index 8a32adc1f6..b022007ddd 100644
--- a/esphome/components/nextion/sensor/__init__.py
+++ b/esphome/components/nextion/sensor/__init__.py
@@ -44,11 +44,11 @@ def _validate(config):
 
 CONFIG_SCHEMA = cv.All(
     sensor.sensor_schema(
+        NextionSensor,
         accuracy_decimals=2,
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(NextionSensor),
             cv.Optional(CONF_PRECISION, default=0): cv.int_range(min=0, max=8),
             cv.Optional(CONF_WAVE_CHANNEL_ID): CheckWaveID,
             cv.Optional(CONF_COMPONENT_ID): cv.uint8_t,
diff --git a/esphome/components/ntc/sensor.py b/esphome/components/ntc/sensor.py
index 660208635c..ba8d3df9d8 100644
--- a/esphome/components/ntc/sensor.py
+++ b/esphome/components/ntc/sensor.py
@@ -5,7 +5,6 @@ import esphome.codegen as cg
 from esphome.components import sensor
 from esphome.const import (
     CONF_CALIBRATION,
-    CONF_ID,
     CONF_REFERENCE_RESISTANCE,
     CONF_REFERENCE_TEMPERATURE,
     CONF_SENSOR,
@@ -117,6 +116,7 @@ def process_calibration(value):
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        NTC,
         unit_of_measurement=UNIT_CELSIUS,
         accuracy_decimals=1,
         device_class=DEVICE_CLASS_TEMPERATURE,
@@ -124,7 +124,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(NTC),
             cv.Required(CONF_SENSOR): cv.use_id(sensor.Sensor),
             cv.Required(CONF_CALIBRATION): process_calibration,
         }
@@ -134,9 +133,8 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
 
     sens = await cg.get_variable(config[CONF_SENSOR])
     cg.add(var.set_sensor(sens))
diff --git a/esphome/components/pid/sensor/__init__.py b/esphome/components/pid/sensor/__init__.py
index d1007fcbc4..d1c65dfb39 100644
--- a/esphome/components/pid/sensor/__init__.py
+++ b/esphome/components/pid/sensor/__init__.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import sensor
 from esphome.const import (
-    CONF_ID,
     STATE_CLASS_MEASUREMENT,
     UNIT_PERCENT,
     ICON_GAUGE,
@@ -29,6 +28,7 @@ PID_CLIMATE_SENSOR_TYPES = {
 CONF_CLIMATE_ID = "climate_id"
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        PIDClimateSensor,
         unit_of_measurement=UNIT_PERCENT,
         icon=ICON_GAUGE,
         accuracy_decimals=1,
@@ -36,7 +36,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(PIDClimateSensor),
             cv.GenerateID(CONF_CLIMATE_ID): cv.use_id(PIDClimate),
             cv.Required(CONF_TYPE): cv.enum(PID_CLIMATE_SENSOR_TYPES, upper=True),
         }
@@ -47,8 +46,7 @@ CONFIG_SCHEMA = (
 
 async def to_code(config):
     parent = await cg.get_variable(config[CONF_CLIMATE_ID])
-    var = cg.new_Pvariable(config[CONF_ID])
-    await sensor.register_sensor(var, config)
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
 
     cg.add(var.set_parent(parent))
diff --git a/esphome/components/pipsolar/sensor/__init__.py b/esphome/components/pipsolar/sensor/__init__.py
index a206e41988..3a6f94d6ac 100644
--- a/esphome/components/pipsolar/sensor/__init__.py
+++ b/esphome/components/pipsolar/sensor/__init__.py
@@ -3,18 +3,15 @@ import esphome.config_validation as cv
 from esphome.components import sensor
 from esphome.const import (
     DEVICE_CLASS_CURRENT,
-    DEVICE_CLASS_EMPTY,
     DEVICE_CLASS_POWER,
     DEVICE_CLASS_TEMPERATURE,
     DEVICE_CLASS_VOLTAGE,
     ICON_CURRENT_AC,
-    ICON_EMPTY,
     UNIT_AMPERE,
     UNIT_CELSIUS,
     UNIT_HERTZ,
     UNIT_PERCENT,
     UNIT_VOLT,
-    UNIT_EMPTY,
     UNIT_VOLT_AMPS,
     UNIT_WATT,
     CONF_BUS_VOLTAGE,
@@ -74,134 +71,196 @@ CONF_PV_CHARGING_POWER = "pv_charging_power"
 
 TYPES = {
     CONF_GRID_RATING_VOLTAGE: sensor.sensor_schema(
-        UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
+        unit_of_measurement=UNIT_VOLT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_VOLTAGE,
     ),
     CONF_GRID_RATING_CURRENT: sensor.sensor_schema(
-        UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT
+        unit_of_measurement=UNIT_AMPERE,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_CURRENT,
     ),
     CONF_AC_OUTPUT_RATING_VOLTAGE: sensor.sensor_schema(
-        UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
+        unit_of_measurement=UNIT_VOLT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_VOLTAGE,
     ),
     CONF_AC_OUTPUT_RATING_FREQUENCY: sensor.sensor_schema(
-        UNIT_HERTZ, ICON_CURRENT_AC, 1, DEVICE_CLASS_EMPTY
+        unit_of_measurement=UNIT_HERTZ,
+        icon=ICON_CURRENT_AC,
+        accuracy_decimals=1,
     ),
     CONF_AC_OUTPUT_RATING_CURRENT: sensor.sensor_schema(
-        UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT
+        unit_of_measurement=UNIT_AMPERE,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_CURRENT,
     ),
     CONF_AC_OUTPUT_RATING_APPARENT_POWER: sensor.sensor_schema(
-        UNIT_VOLT_AMPS, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        unit_of_measurement=UNIT_VOLT_AMPS,
+        accuracy_decimals=1,
     ),
     CONF_AC_OUTPUT_RATING_ACTIVE_POWER: sensor.sensor_schema(
-        UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER
+        unit_of_measurement=UNIT_WATT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_POWER,
     ),
     CONF_BATTERY_RATING_VOLTAGE: sensor.sensor_schema(
-        UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
+        unit_of_measurement=UNIT_VOLT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_VOLTAGE,
     ),
     CONF_BATTERY_RECHARGE_VOLTAGE: sensor.sensor_schema(
-        UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
+        unit_of_measurement=UNIT_VOLT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_VOLTAGE,
     ),
     CONF_BATTERY_UNDER_VOLTAGE: sensor.sensor_schema(
-        UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
+        unit_of_measurement=UNIT_VOLT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_VOLTAGE,
     ),
     CONF_BATTERY_BULK_VOLTAGE: sensor.sensor_schema(
-        UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
+        unit_of_measurement=UNIT_VOLT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_VOLTAGE,
     ),
     CONF_BATTERY_FLOAT_VOLTAGE: sensor.sensor_schema(
-        UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
+        unit_of_measurement=UNIT_VOLT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_VOLTAGE,
     ),
     CONF_BATTERY_TYPE: sensor.sensor_schema(
-        UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        accuracy_decimals=1,
     ),
     CONF_CURRENT_MAX_AC_CHARGING_CURRENT: sensor.sensor_schema(
-        UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT
+        unit_of_measurement=UNIT_AMPERE,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_CURRENT,
     ),
     CONF_CURRENT_MAX_CHARGING_CURRENT: sensor.sensor_schema(
-        UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT
+        unit_of_measurement=UNIT_AMPERE,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_CURRENT,
     ),
     CONF_INPUT_VOLTAGE_RANGE: sensor.sensor_schema(
-        UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        accuracy_decimals=1,
     ),
     CONF_OUTPUT_SOURCE_PRIORITY: sensor.sensor_schema(
-        UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        accuracy_decimals=1,
     ),
     CONF_CHARGER_SOURCE_PRIORITY: sensor.sensor_schema(
-        UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        accuracy_decimals=1,
     ),
     CONF_PARALLEL_MAX_NUM: sensor.sensor_schema(
-        UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        accuracy_decimals=1,
     ),
     CONF_MACHINE_TYPE: sensor.sensor_schema(
-        UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        accuracy_decimals=1,
+    ),
+    CONF_TOPOLOGY: sensor.sensor_schema(
+        accuracy_decimals=1,
     ),
-    CONF_TOPOLOGY: sensor.sensor_schema(UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY),
     CONF_OUTPUT_MODE: sensor.sensor_schema(
-        UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        accuracy_decimals=1,
     ),
     CONF_BATTERY_REDISCHARGE_VOLTAGE: sensor.sensor_schema(
-        UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        accuracy_decimals=1,
     ),
     CONF_PV_OK_CONDITION_FOR_PARALLEL: sensor.sensor_schema(
-        UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        accuracy_decimals=1,
     ),
     CONF_PV_POWER_BALANCE: sensor.sensor_schema(
-        UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        accuracy_decimals=1,
     ),
     CONF_GRID_VOLTAGE: sensor.sensor_schema(
-        UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
+        unit_of_measurement=UNIT_VOLT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_VOLTAGE,
     ),
     CONF_GRID_FREQUENCY: sensor.sensor_schema(
-        UNIT_HERTZ, ICON_CURRENT_AC, 1, DEVICE_CLASS_EMPTY
+        unit_of_measurement=UNIT_HERTZ,
+        icon=ICON_CURRENT_AC,
+        accuracy_decimals=1,
     ),
     CONF_AC_OUTPUT_VOLTAGE: sensor.sensor_schema(
-        UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
+        unit_of_measurement=UNIT_VOLT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_VOLTAGE,
     ),
     CONF_AC_OUTPUT_FREQUENCY: sensor.sensor_schema(
-        UNIT_HERTZ, ICON_CURRENT_AC, 1, DEVICE_CLASS_EMPTY
+        unit_of_measurement=UNIT_HERTZ,
+        icon=ICON_CURRENT_AC,
+        accuracy_decimals=1,
     ),
     CONF_AC_OUTPUT_APPARENT_POWER: sensor.sensor_schema(
-        UNIT_VOLT_AMPS, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        unit_of_measurement=UNIT_VOLT_AMPS,
+        accuracy_decimals=1,
     ),
     CONF_AC_OUTPUT_ACTIVE_POWER: sensor.sensor_schema(
-        UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER
+        unit_of_measurement=UNIT_WATT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_POWER,
     ),
     CONF_OUTPUT_LOAD_PERCENT: sensor.sensor_schema(
-        UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        unit_of_measurement=UNIT_PERCENT,
+        accuracy_decimals=1,
     ),
     CONF_BUS_VOLTAGE: sensor.sensor_schema(
-        UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
+        unit_of_measurement=UNIT_VOLT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_VOLTAGE,
     ),
     CONF_BATTERY_VOLTAGE: sensor.sensor_schema(
-        UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
+        unit_of_measurement=UNIT_VOLT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_VOLTAGE,
     ),
     CONF_BATTERY_CHARGING_CURRENT: sensor.sensor_schema(
-        UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT
+        unit_of_measurement=UNIT_AMPERE,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_CURRENT,
     ),
     CONF_BATTERY_CAPACITY_PERCENT: sensor.sensor_schema(
-        UNIT_PERCENT, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        unit_of_measurement=UNIT_PERCENT,
+        accuracy_decimals=1,
     ),
     CONF_INVERTER_HEAT_SINK_TEMPERATURE: sensor.sensor_schema(
-        UNIT_CELSIUS, ICON_EMPTY, 1, DEVICE_CLASS_TEMPERATURE
+        unit_of_measurement=UNIT_CELSIUS,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_TEMPERATURE,
     ),
     CONF_PV_INPUT_CURRENT_FOR_BATTERY: sensor.sensor_schema(
-        UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT
+        unit_of_measurement=UNIT_AMPERE,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_CURRENT,
     ),
     CONF_PV_INPUT_VOLTAGE: sensor.sensor_schema(
-        UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
+        unit_of_measurement=UNIT_VOLT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_VOLTAGE,
     ),
     CONF_BATTERY_VOLTAGE_SCC: sensor.sensor_schema(
-        UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
+        unit_of_measurement=UNIT_VOLT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_VOLTAGE,
     ),
     CONF_BATTERY_DISCHARGE_CURRENT: sensor.sensor_schema(
-        UNIT_AMPERE, ICON_EMPTY, 1, DEVICE_CLASS_CURRENT
+        unit_of_measurement=UNIT_AMPERE,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_CURRENT,
     ),
     CONF_BATTERY_VOLTAGE_OFFSET_FOR_FANS_ON: sensor.sensor_schema(
-        UNIT_VOLT, ICON_EMPTY, 1, DEVICE_CLASS_VOLTAGE
+        unit_of_measurement=UNIT_VOLT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_VOLTAGE,
     ),
     CONF_EEPROM_VERSION: sensor.sensor_schema(
-        UNIT_EMPTY, ICON_EMPTY, 1, DEVICE_CLASS_EMPTY
+        accuracy_decimals=1,
     ),
     CONF_PV_CHARGING_POWER: sensor.sensor_schema(
-        UNIT_WATT, ICON_EMPTY, 1, DEVICE_CLASS_POWER
+        unit_of_measurement=UNIT_WATT,
+        accuracy_decimals=1,
+        device_class=DEVICE_CLASS_POWER,
     ),
 }
 
diff --git a/esphome/components/pmsx003/sensor.py b/esphome/components/pmsx003/sensor.py
index 56a91d22fc..b731e48e31 100644
--- a/esphome/components/pmsx003/sensor.py
+++ b/esphome/components/pmsx003/sensor.py
@@ -22,7 +22,6 @@ from esphome.const import (
     DEVICE_CLASS_PM1,
     DEVICE_CLASS_PM10,
     DEVICE_CLASS_PM25,
-    DEVICE_CLASS_EMPTY,
     DEVICE_CLASS_HUMIDITY,
     DEVICE_CLASS_TEMPERATURE,
     ICON_CHEMICAL_WEAPON,
@@ -75,22 +74,22 @@ CONFIG_SCHEMA = (
             cv.GenerateID(): cv.declare_id(PMSX003Component),
             cv.Required(CONF_TYPE): cv.enum(PMSX003_TYPES, upper=True),
             cv.Optional(CONF_PM_1_0_STD): sensor.sensor_schema(
-                UNIT_MICROGRAMS_PER_CUBIC_METER,
-                ICON_CHEMICAL_WEAPON,
-                0,
-                DEVICE_CLASS_PM1,
+                unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER,
+                icon=ICON_CHEMICAL_WEAPON,
+                accuracy_decimals=0,
+                device_class=DEVICE_CLASS_PM1,
             ),
             cv.Optional(CONF_PM_2_5_STD): sensor.sensor_schema(
-                UNIT_MICROGRAMS_PER_CUBIC_METER,
-                ICON_CHEMICAL_WEAPON,
-                0,
-                DEVICE_CLASS_PM25,
+                unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER,
+                icon=ICON_CHEMICAL_WEAPON,
+                accuracy_decimals=0,
+                device_class=DEVICE_CLASS_PM25,
             ),
             cv.Optional(CONF_PM_10_0_STD): sensor.sensor_schema(
-                UNIT_MICROGRAMS_PER_CUBIC_METER,
-                ICON_CHEMICAL_WEAPON,
-                0,
-                DEVICE_CLASS_PM10,
+                unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER,
+                icon=ICON_CHEMICAL_WEAPON,
+                accuracy_decimals=0,
+                device_class=DEVICE_CLASS_PM10,
             ),
             cv.Optional(CONF_PM_1_0): sensor.sensor_schema(
                 unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER,
@@ -111,40 +110,34 @@ CONFIG_SCHEMA = (
                 state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_PM_0_3UM): sensor.sensor_schema(
-                UNIT_COUNT_DECILITRE,
-                ICON_CHEMICAL_WEAPON,
-                0,
-                DEVICE_CLASS_EMPTY,
+                unit_of_measurement=UNIT_COUNT_DECILITRE,
+                icon=ICON_CHEMICAL_WEAPON,
+                accuracy_decimals=0,
             ),
             cv.Optional(CONF_PM_0_5UM): sensor.sensor_schema(
-                UNIT_COUNT_DECILITRE,
-                ICON_CHEMICAL_WEAPON,
-                0,
-                DEVICE_CLASS_EMPTY,
+                unit_of_measurement=UNIT_COUNT_DECILITRE,
+                icon=ICON_CHEMICAL_WEAPON,
+                accuracy_decimals=0,
             ),
             cv.Optional(CONF_PM_1_0UM): sensor.sensor_schema(
-                UNIT_COUNT_DECILITRE,
-                ICON_CHEMICAL_WEAPON,
-                0,
-                DEVICE_CLASS_EMPTY,
+                unit_of_measurement=UNIT_COUNT_DECILITRE,
+                icon=ICON_CHEMICAL_WEAPON,
+                accuracy_decimals=0,
             ),
             cv.Optional(CONF_PM_2_5UM): sensor.sensor_schema(
-                UNIT_COUNT_DECILITRE,
-                ICON_CHEMICAL_WEAPON,
-                0,
-                DEVICE_CLASS_EMPTY,
+                unit_of_measurement=UNIT_COUNT_DECILITRE,
+                icon=ICON_CHEMICAL_WEAPON,
+                accuracy_decimals=0,
             ),
             cv.Optional(CONF_PM_5_0UM): sensor.sensor_schema(
-                UNIT_COUNT_DECILITRE,
-                ICON_CHEMICAL_WEAPON,
-                0,
-                DEVICE_CLASS_EMPTY,
+                unit_of_measurement=UNIT_COUNT_DECILITRE,
+                icon=ICON_CHEMICAL_WEAPON,
+                accuracy_decimals=0,
             ),
             cv.Optional(CONF_PM_10_0UM): sensor.sensor_schema(
-                UNIT_COUNT_DECILITRE,
-                ICON_CHEMICAL_WEAPON,
-                0,
-                DEVICE_CLASS_EMPTY,
+                unit_of_measurement=UNIT_COUNT_DECILITRE,
+                icon=ICON_CHEMICAL_WEAPON,
+                accuracy_decimals=0,
             ),
             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
                 unit_of_measurement=UNIT_CELSIUS,
diff --git a/esphome/components/pulse_counter/sensor.py b/esphome/components/pulse_counter/sensor.py
index c7b89d41b0..6dcb974a1f 100644
--- a/esphome/components/pulse_counter/sensor.py
+++ b/esphome/components/pulse_counter/sensor.py
@@ -5,7 +5,6 @@ from esphome.components import sensor
 from esphome.const import (
     CONF_COUNT_MODE,
     CONF_FALLING_EDGE,
-    CONF_ID,
     CONF_INTERNAL_FILTER,
     CONF_PIN,
     CONF_RISING_EDGE,
@@ -66,6 +65,7 @@ def validate_count_mode(value):
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        PulseCounterSensor,
         unit_of_measurement=UNIT_PULSES_PER_MINUTE,
         icon=ICON_PULSE,
         accuracy_decimals=2,
@@ -73,7 +73,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(PulseCounterSensor),
             cv.Required(CONF_PIN): validate_pulse_counter_pin,
             cv.Optional(
                 CONF_COUNT_MODE,
@@ -104,9 +103,8 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
 
     pin = await cg.gpio_pin_expression(config[CONF_PIN])
     cg.add(var.set_pin(pin))
diff --git a/esphome/components/pulse_meter/sensor.py b/esphome/components/pulse_meter/sensor.py
index 454cb3a69d..fa753b5b05 100644
--- a/esphome/components/pulse_meter/sensor.py
+++ b/esphome/components/pulse_meter/sensor.py
@@ -50,13 +50,13 @@ def validate_pulse_meter_pin(value):
 
 
 CONFIG_SCHEMA = sensor.sensor_schema(
+    PulseMeterSensor,
     unit_of_measurement=UNIT_PULSES_PER_MINUTE,
     icon=ICON_PULSE,
     accuracy_decimals=2,
     state_class=STATE_CLASS_MEASUREMENT,
 ).extend(
     {
-        cv.GenerateID(): cv.declare_id(PulseMeterSensor),
         cv.Required(CONF_PIN): validate_pulse_meter_pin,
         cv.Optional(CONF_INTERNAL_FILTER, default="13us"): validate_internal_filter,
         cv.Optional(CONF_TIMEOUT, default="5min"): validate_timeout,
@@ -71,9 +71,8 @@ CONFIG_SCHEMA = sensor.sensor_schema(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
 
     pin = await cg.gpio_pin_expression(config[CONF_PIN])
     cg.add(var.set_pin(pin))
diff --git a/esphome/components/pulse_width/sensor.py b/esphome/components/pulse_width/sensor.py
index b090647627..47d70166d3 100644
--- a/esphome/components/pulse_width/sensor.py
+++ b/esphome/components/pulse_width/sensor.py
@@ -3,7 +3,6 @@ import esphome.config_validation as cv
 from esphome import pins
 from esphome.components import sensor
 from esphome.const import (
-    CONF_ID,
     CONF_PIN,
     STATE_CLASS_MEASUREMENT,
     UNIT_SECOND,
@@ -18,6 +17,7 @@ PulseWidthSensor = pulse_width_ns.class_(
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        PulseWidthSensor,
         unit_of_measurement=UNIT_SECOND,
         icon=ICON_TIMER,
         accuracy_decimals=3,
@@ -25,7 +25,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(PulseWidthSensor),
             cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema),
         }
     )
@@ -34,9 +33,8 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
 
     pin = await cg.gpio_pin_expression(config[CONF_PIN])
     cg.add(var.set_pin(pin))
diff --git a/esphome/components/qmc5883l/sensor.py b/esphome/components/qmc5883l/sensor.py
index 27d1df5b29..100ac93520 100644
--- a/esphome/components/qmc5883l/sensor.py
+++ b/esphome/components/qmc5883l/sensor.py
@@ -8,7 +8,6 @@ from esphome.const import (
     CONF_RANGE,
     ICON_MAGNET,
     STATE_CLASS_MEASUREMENT,
-    STATE_CLASS_NONE,
     UNIT_MICROTESLA,
     UNIT_DEGREES,
     ICON_SCREEN_ROTATION,
@@ -79,7 +78,6 @@ heading_schema = sensor.sensor_schema(
     unit_of_measurement=UNIT_DEGREES,
     icon=ICON_SCREEN_ROTATION,
     accuracy_decimals=1,
-    state_class=STATE_CLASS_NONE,
 )
 
 CONFIG_SCHEMA = (
diff --git a/esphome/components/resistance/sensor.py b/esphome/components/resistance/sensor.py
index 329192e902..55e7ddfc81 100644
--- a/esphome/components/resistance/sensor.py
+++ b/esphome/components/resistance/sensor.py
@@ -6,7 +6,6 @@ from esphome.const import (
     STATE_CLASS_MEASUREMENT,
     UNIT_OHM,
     ICON_FLASH,
-    CONF_ID,
 )
 
 resistance_ns = cg.esphome_ns.namespace("resistance")
@@ -24,6 +23,7 @@ CONFIGURATIONS = {
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        ResistanceSensor,
         unit_of_measurement=UNIT_OHM,
         icon=ICON_FLASH,
         accuracy_decimals=1,
@@ -31,7 +31,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(ResistanceSensor),
             cv.Required(CONF_SENSOR): cv.use_id(sensor.Sensor),
             cv.Required(CONF_CONFIGURATION): cv.enum(CONFIGURATIONS, upper=True),
             cv.Required(CONF_RESISTOR): cv.resistance,
@@ -43,9 +42,8 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
 
     sens = await cg.get_variable(config[CONF_SENSOR])
     cg.add(var.set_sensor(sens))
diff --git a/esphome/components/rotary_encoder/sensor.py b/esphome/components/rotary_encoder/sensor.py
index cd747264b3..ae6b0ae3bf 100644
--- a/esphome/components/rotary_encoder/sensor.py
+++ b/esphome/components/rotary_encoder/sensor.py
@@ -7,7 +7,6 @@ from esphome.const import (
     CONF_RESOLUTION,
     CONF_MIN_VALUE,
     CONF_MAX_VALUE,
-    STATE_CLASS_NONE,
     UNIT_STEPS,
     ICON_ROTATE_RIGHT,
     CONF_VALUE,
@@ -65,14 +64,13 @@ def validate_min_max_value(config):
 
 CONFIG_SCHEMA = cv.All(
     sensor.sensor_schema(
+        RotaryEncoderSensor,
         unit_of_measurement=UNIT_STEPS,
         icon=ICON_ROTATE_RIGHT,
         accuracy_decimals=0,
-        state_class=STATE_CLASS_NONE,
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(RotaryEncoderSensor),
             cv.Required(CONF_PIN_A): cv.All(pins.internal_gpio_input_pin_schema),
             cv.Required(CONF_PIN_B): cv.All(pins.internal_gpio_input_pin_schema),
             cv.Optional(CONF_PIN_RESET): pins.internal_gpio_output_pin_schema,
@@ -105,9 +103,9 @@ CONFIG_SCHEMA = cv.All(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
+
     pin_a = await cg.gpio_pin_expression(config[CONF_PIN_A])
     cg.add(var.set_pin_a(pin_a))
     pin_b = await cg.gpio_pin_expression(config[CONF_PIN_B])
diff --git a/esphome/components/ruuvitag/sensor.py b/esphome/components/ruuvitag/sensor.py
index 2bb9549195..a46daf88ac 100644
--- a/esphome/components/ruuvitag/sensor.py
+++ b/esphome/components/ruuvitag/sensor.py
@@ -21,7 +21,6 @@ from esphome.const import (
     DEVICE_CLASS_VOLTAGE,
     ENTITY_CATEGORY_DIAGNOSTIC,
     STATE_CLASS_MEASUREMENT,
-    STATE_CLASS_NONE,
     UNIT_CELSIUS,
     UNIT_PERCENT,
     UNIT_VOLT,
@@ -108,13 +107,11 @@ CONFIG_SCHEMA = (
             cv.Optional(CONF_MOVEMENT_COUNTER): sensor.sensor_schema(
                 icon=ICON_GAUGE,
                 accuracy_decimals=0,
-                state_class=STATE_CLASS_NONE,
                 entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
             ),
             cv.Optional(CONF_MEASUREMENT_SEQUENCE_NUMBER): sensor.sensor_schema(
                 icon=ICON_GAUGE,
                 accuracy_decimals=0,
-                state_class=STATE_CLASS_NONE,
                 entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
             ),
         }
diff --git a/esphome/components/sdp3x/sensor.py b/esphome/components/sdp3x/sensor.py
index 45f5cc4d9a..66ee475b11 100644
--- a/esphome/components/sdp3x/sensor.py
+++ b/esphome/components/sdp3x/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import i2c, sensor
 from esphome.const import (
-    CONF_ID,
     DEVICE_CLASS_PRESSURE,
     STATE_CLASS_MEASUREMENT,
     UNIT_HECTOPASCAL,
@@ -24,6 +23,7 @@ CONF_MEASUREMENT_MODE = "measurement_mode"
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        SDP3XComponent,
         unit_of_measurement=UNIT_HECTOPASCAL,
         accuracy_decimals=3,
         device_class=DEVICE_CLASS_PRESSURE,
@@ -31,7 +31,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(SDP3XComponent),
             cv.Optional(
                 CONF_MEASUREMENT_MODE, default="differential_pressure"
             ): cv.enum(MEASUREMENT_MODE),
@@ -43,8 +42,7 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
     await i2c.register_i2c_device(var, config)
-    await sensor.register_sensor(var, config)
     cg.add(var.set_measurement_mode(config[CONF_MEASUREMENT_MODE]))
diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py
index 14a15da2f1..577596f6ce 100644
--- a/esphome/components/sensor/__init__.py
+++ b/esphome/components/sensor/__init__.py
@@ -58,6 +58,7 @@ from esphome.const import (
     DEVICE_CLASS_VOLTAGE,
 )
 from esphome.core import CORE, coroutine_with_priority
+from esphome.cpp_generator import MockObjClass
 from esphome.cpp_helpers import setup_entity
 from esphome.util import Registry
 
@@ -223,6 +224,8 @@ _UNDEF = object()
 
 
 def sensor_schema(
+    class_: MockObjClass = _UNDEF,
+    *,
     unit_of_measurement: str = _UNDEF,
     icon: str = _UNDEF,
     accuracy_decimals: int = _UNDEF,
@@ -231,6 +234,8 @@ def sensor_schema(
     entity_category: str = _UNDEF,
 ) -> cv.Schema:
     schema = SENSOR_SCHEMA
+    if class_ is not _UNDEF:
+        schema = schema.extend({cv.GenerateID(): cv.declare_id(class_)})
     if unit_of_measurement is not _UNDEF:
         schema = schema.extend(
             {
diff --git a/esphome/components/sgp40/sensor.py b/esphome/components/sgp40/sensor.py
index 7b96f867af..6f27b54fb0 100644
--- a/esphome/components/sgp40/sensor.py
+++ b/esphome/components/sgp40/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import i2c, sensor
 from esphome.const import (
-    CONF_ID,
     ICON_RADIATOR,
     DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS,
     STATE_CLASS_MEASUREMENT,
@@ -25,6 +24,7 @@ CONF_VOC_BASELINE = "voc_baseline"
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        SGP40Component,
         icon=ICON_RADIATOR,
         accuracy_decimals=0,
         device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS,
@@ -32,7 +32,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(SGP40Component),
             cv.Optional(CONF_STORE_BASELINE, default=True): cv.boolean,
             cv.Optional(CONF_VOC_BASELINE): cv.hex_uint16_t,
             cv.Optional(CONF_COMPENSATION): cv.Schema(
@@ -49,10 +48,9 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
     await i2c.register_i2c_device(var, config)
-    await sensor.register_sensor(var, config)
 
     if CONF_COMPENSATION in config:
         compensation_config = config[CONF_COMPENSATION]
diff --git a/esphome/components/sts3x/sensor.py b/esphome/components/sts3x/sensor.py
index b02c835ef8..aa7573aaf2 100644
--- a/esphome/components/sts3x/sensor.py
+++ b/esphome/components/sts3x/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import i2c, sensor
 from esphome.const import (
-    CONF_ID,
     DEVICE_CLASS_TEMPERATURE,
     STATE_CLASS_MEASUREMENT,
     UNIT_CELSIUS,
@@ -18,23 +17,18 @@ STS3XComponent = sts3x_ns.class_(
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        STS3XComponent,
         unit_of_measurement=UNIT_CELSIUS,
         accuracy_decimals=1,
         device_class=DEVICE_CLASS_TEMPERATURE,
         state_class=STATE_CLASS_MEASUREMENT,
     )
-    .extend(
-        {
-            cv.GenerateID(): cv.declare_id(STS3XComponent),
-        }
-    )
     .extend(cv.polling_component_schema("60s"))
     .extend(i2c.i2c_device_schema(0x4A))
 )
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
     await i2c.register_i2c_device(var, config)
diff --git a/esphome/components/sun/sensor/__init__.py b/esphome/components/sun/sensor/__init__.py
index 236acfadef..10c0237327 100644
--- a/esphome/components/sun/sensor/__init__.py
+++ b/esphome/components/sun/sensor/__init__.py
@@ -2,10 +2,8 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import sensor
 from esphome.const import (
-    STATE_CLASS_NONE,
     UNIT_DEGREES,
     ICON_WEATHER_SUNSET,
-    CONF_ID,
     CONF_TYPE,
 )
 from .. import sun_ns, CONF_SUN_ID, Sun
@@ -21,14 +19,13 @@ TYPES = {
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        SunSensor,
         unit_of_measurement=UNIT_DEGREES,
         icon=ICON_WEATHER_SUNSET,
         accuracy_decimals=1,
-        state_class=STATE_CLASS_NONE,
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(SunSensor),
             cv.GenerateID(CONF_SUN_ID): cv.use_id(Sun),
             cv.Required(CONF_TYPE): cv.enum(TYPES, lower=True),
         }
@@ -38,9 +35,8 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
 
     cg.add(var.set_type(config[CONF_TYPE]))
     paren = await cg.get_variable(config[CONF_SUN_ID])
diff --git a/esphome/components/teleinfo/sensor/__init__.py b/esphome/components/teleinfo/sensor/__init__.py
index aa875be157..ff2d81c95e 100644
--- a/esphome/components/teleinfo/sensor/__init__.py
+++ b/esphome/components/teleinfo/sensor/__init__.py
@@ -1,5 +1,4 @@
 import esphome.codegen as cg
-import esphome.config_validation as cv
 from esphome.components import sensor
 from esphome.const import CONF_ID, ICON_FLASH, UNIT_WATT_HOURS
 
@@ -13,13 +12,12 @@ from .. import (
 
 TeleInfoSensor = teleinfo_ns.class_("TeleInfoSensor", sensor.Sensor, cg.Component)
 
-CONFIG_SCHEMA = (
-    sensor.sensor_schema(
-        unit_of_measurement=UNIT_WATT_HOURS, icon=ICON_FLASH, accuracy_decimals=0
-    )
-    .extend({cv.GenerateID(): cv.declare_id(TeleInfoSensor)})
-    .extend(TELEINFO_LISTENER_SCHEMA)
-)
+CONFIG_SCHEMA = sensor.sensor_schema(
+    TeleInfoSensor,
+    unit_of_measurement=UNIT_WATT_HOURS,
+    icon=ICON_FLASH,
+    accuracy_decimals=0,
+).extend(TELEINFO_LISTENER_SCHEMA)
 
 
 async def to_code(config):
diff --git a/esphome/components/template/sensor/__init__.py b/esphome/components/template/sensor/__init__.py
index 75fb505d91..9ed7a83848 100644
--- a/esphome/components/template/sensor/__init__.py
+++ b/esphome/components/template/sensor/__init__.py
@@ -6,7 +6,6 @@ from esphome.const import (
     CONF_ID,
     CONF_LAMBDA,
     CONF_STATE,
-    STATE_CLASS_NONE,
 )
 from .. import template_ns
 
@@ -16,12 +15,11 @@ TemplateSensor = template_ns.class_(
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        TemplateSensor,
         accuracy_decimals=1,
-        state_class=STATE_CLASS_NONE,
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(TemplateSensor),
             cv.Optional(CONF_LAMBDA): cv.returning_lambda,
         }
     )
@@ -30,9 +28,8 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
 
     if CONF_LAMBDA in config:
         template_ = await cg.process_lambda(
diff --git a/esphome/components/tmp102/sensor.py b/esphome/components/tmp102/sensor.py
index c5ffbb8df5..57d0afd5a1 100644
--- a/esphome/components/tmp102/sensor.py
+++ b/esphome/components/tmp102/sensor.py
@@ -11,7 +11,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import i2c, sensor
 from esphome.const import (
-    CONF_ID,
     DEVICE_CLASS_TEMPERATURE,
     STATE_CLASS_MEASUREMENT,
     UNIT_CELSIUS,
@@ -27,23 +26,18 @@ TMP102Component = tmp102_ns.class_(
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        TMP102Component,
         unit_of_measurement=UNIT_CELSIUS,
         accuracy_decimals=1,
         device_class=DEVICE_CLASS_TEMPERATURE,
         state_class=STATE_CLASS_MEASUREMENT,
     )
-    .extend(
-        {
-            cv.GenerateID(): cv.declare_id(TMP102Component),
-        }
-    )
     .extend(cv.polling_component_schema("60s"))
     .extend(i2c.i2c_device_schema(0x48))
 )
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
     await i2c.register_i2c_device(var, config)
-    await sensor.register_sensor(var, config)
diff --git a/esphome/components/tmp117/sensor.py b/esphome/components/tmp117/sensor.py
index 054864dd83..fb97258bc1 100644
--- a/esphome/components/tmp117/sensor.py
+++ b/esphome/components/tmp117/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import i2c, sensor
 from esphome.const import (
-    CONF_ID,
     CONF_UPDATE_INTERVAL,
     DEVICE_CLASS_TEMPERATURE,
     STATE_CLASS_MEASUREMENT,
@@ -19,16 +18,12 @@ TMP117Component = tmp117_ns.class_(
 
 CONFIG_SCHEMA = cv.All(
     sensor.sensor_schema(
+        TMP117Component,
         unit_of_measurement=UNIT_CELSIUS,
         accuracy_decimals=1,
         device_class=DEVICE_CLASS_TEMPERATURE,
         state_class=STATE_CLASS_MEASUREMENT,
     )
-    .extend(
-        {
-            cv.GenerateID(): cv.declare_id(TMP117Component),
-        }
-    )
     .extend(cv.polling_component_schema("60s"))
     .extend(i2c.i2c_device_schema(0x48))
 )
@@ -77,10 +72,9 @@ def determine_config_register(polling_period):
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
     await i2c.register_i2c_device(var, config)
-    await sensor.register_sensor(var, config)
 
     update_period = config[CONF_UPDATE_INTERVAL].total_seconds
     cg.add(var.set_config(determine_config_register(update_period)))
diff --git a/esphome/components/tof10120/sensor.py b/esphome/components/tof10120/sensor.py
index 2d3add2399..21d6d48659 100644
--- a/esphome/components/tof10120/sensor.py
+++ b/esphome/components/tof10120/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import i2c, sensor
 from esphome.const import (
-    CONF_ID,
     STATE_CLASS_MEASUREMENT,
     UNIT_METER,
     ICON_ARROW_EXPAND_VERTICAL,
@@ -18,19 +17,18 @@ TOF10120Sensor = tof10120_ns.class_(
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        TOF10120Sensor,
         unit_of_measurement=UNIT_METER,
         icon=ICON_ARROW_EXPAND_VERTICAL,
         accuracy_decimals=3,
         state_class=STATE_CLASS_MEASUREMENT,
     )
-    .extend({cv.GenerateID(): cv.declare_id(TOF10120Sensor)})
     .extend(cv.polling_component_schema("60s"))
     .extend(i2c.i2c_device_schema(0x52))
 )
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
     await i2c.register_i2c_device(var, config)
diff --git a/esphome/components/total_daily_energy/sensor.py b/esphome/components/total_daily_energy/sensor.py
index 1af8db8332..3698563aff 100644
--- a/esphome/components/total_daily_energy/sensor.py
+++ b/esphome/components/total_daily_energy/sensor.py
@@ -40,12 +40,12 @@ def inherit_accuracy_decimals(decimals, config):
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        TotalDailyEnergy,
         device_class=DEVICE_CLASS_ENERGY,
         state_class=STATE_CLASS_TOTAL_INCREASING,
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(TotalDailyEnergy),
             cv.GenerateID(CONF_TIME_ID): cv.use_id(time.RealTimeClock),
             cv.Required(CONF_POWER_ID): cv.use_id(sensor.Sensor),
             cv.Optional(CONF_RESTORE, default=True): cv.boolean,
@@ -82,10 +82,8 @@ FINAL_VALIDATE_SCHEMA = cv.All(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
-
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
 
     sens = await cg.get_variable(config[CONF_POWER_ID])
     cg.add(var.set_parent(sens))
diff --git a/esphome/components/tsl2561/sensor.py b/esphome/components/tsl2561/sensor.py
index cf3837cb4d..fb2c00697b 100644
--- a/esphome/components/tsl2561/sensor.py
+++ b/esphome/components/tsl2561/sensor.py
@@ -3,7 +3,6 @@ import esphome.config_validation as cv
 from esphome.components import i2c, sensor
 from esphome.const import (
     CONF_GAIN,
-    CONF_ID,
     CONF_INTEGRATION_TIME,
     DEVICE_CLASS_ILLUMINANCE,
     STATE_CLASS_MEASUREMENT,
@@ -40,6 +39,7 @@ TSL2561Sensor = tsl2561_ns.class_(
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        TSL2561Sensor,
         unit_of_measurement=UNIT_LUX,
         accuracy_decimals=1,
         device_class=DEVICE_CLASS_ILLUMINANCE,
@@ -47,7 +47,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(TSL2561Sensor),
             cv.Optional(
                 CONF_INTEGRATION_TIME, default="402ms"
             ): validate_integration_time,
@@ -61,10 +60,9 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
     await i2c.register_i2c_device(var, config)
-    await sensor.register_sensor(var, config)
 
     cg.add(var.set_integration_time(config[CONF_INTEGRATION_TIME]))
     cg.add(var.set_gain(config[CONF_GAIN]))
diff --git a/esphome/components/tsl2591/sensor.py b/esphome/components/tsl2591/sensor.py
index 1ec37b5f93..63a0733365 100644
--- a/esphome/components/tsl2591/sensor.py
+++ b/esphome/components/tsl2591/sensor.py
@@ -35,10 +35,8 @@ from esphome.const import (
     CONF_DEVICE_FACTOR,
     CONF_GLASS_ATTENUATION_FACTOR,
     ICON_BRIGHTNESS_6,
-    DEVICE_CLASS_EMPTY,
     DEVICE_CLASS_ILLUMINANCE,
     STATE_CLASS_MEASUREMENT,
-    UNIT_EMPTY,
     UNIT_LUX,
 )
 
@@ -87,32 +85,26 @@ CONFIG_SCHEMA = (
         {
             cv.GenerateID(): cv.declare_id(TSL2591Component),
             cv.Optional(CONF_INFRARED): sensor.sensor_schema(
-                UNIT_EMPTY,
-                ICON_BRIGHTNESS_6,
-                0,
-                DEVICE_CLASS_EMPTY,
-                STATE_CLASS_MEASUREMENT,
+                icon=ICON_BRIGHTNESS_6,
+                accuracy_decimals=0,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_VISIBLE): sensor.sensor_schema(
-                UNIT_EMPTY,
-                ICON_BRIGHTNESS_6,
-                0,
-                DEVICE_CLASS_EMPTY,
-                STATE_CLASS_MEASUREMENT,
+                icon=ICON_BRIGHTNESS_6,
+                accuracy_decimals=0,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_FULL_SPECTRUM): sensor.sensor_schema(
-                UNIT_EMPTY,
-                ICON_BRIGHTNESS_6,
-                0,
-                DEVICE_CLASS_EMPTY,
-                STATE_CLASS_MEASUREMENT,
+                icon=ICON_BRIGHTNESS_6,
+                accuracy_decimals=0,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(CONF_CALCULATED_LUX): sensor.sensor_schema(
-                UNIT_LUX,
-                ICON_BRIGHTNESS_6,
-                4,
-                DEVICE_CLASS_ILLUMINANCE,
-                STATE_CLASS_MEASUREMENT,
+                unit_of_measurement=UNIT_LUX,
+                icon=ICON_BRIGHTNESS_6,
+                accuracy_decimals=4,
+                device_class=DEVICE_CLASS_ILLUMINANCE,
+                state_class=STATE_CLASS_MEASUREMENT,
             ),
             cv.Optional(
                 CONF_INTEGRATION_TIME, default="100ms"
diff --git a/esphome/components/tx20/sensor.py b/esphome/components/tx20/sensor.py
index 84df82b5e6..f8a0b08d99 100644
--- a/esphome/components/tx20/sensor.py
+++ b/esphome/components/tx20/sensor.py
@@ -8,7 +8,6 @@ from esphome.const import (
     CONF_PIN,
     CONF_WIND_DIRECTION_DEGREES,
     STATE_CLASS_MEASUREMENT,
-    STATE_CLASS_NONE,
     UNIT_KILOMETER_PER_HOUR,
     ICON_WEATHER_WINDY,
     ICON_SIGN_DIRECTION,
@@ -31,7 +30,6 @@ CONFIG_SCHEMA = cv.Schema(
             unit_of_measurement=UNIT_DEGREES,
             icon=ICON_SIGN_DIRECTION,
             accuracy_decimals=1,
-            state_class=STATE_CLASS_NONE,
         ),
         cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema),
     }
diff --git a/esphome/components/ultrasonic/sensor.py b/esphome/components/ultrasonic/sensor.py
index f7026e884c..afbd1128c2 100644
--- a/esphome/components/ultrasonic/sensor.py
+++ b/esphome/components/ultrasonic/sensor.py
@@ -4,7 +4,6 @@ from esphome import pins
 from esphome.components import sensor
 from esphome.const import (
     CONF_ECHO_PIN,
-    CONF_ID,
     CONF_TRIGGER_PIN,
     CONF_TIMEOUT,
     STATE_CLASS_MEASUREMENT,
@@ -21,6 +20,7 @@ UltrasonicSensorComponent = ultrasonic_ns.class_(
 
 CONFIG_SCHEMA = (
     sensor.sensor_schema(
+        UltrasonicSensorComponent,
         unit_of_measurement=UNIT_METER,
         icon=ICON_ARROW_EXPAND_VERTICAL,
         accuracy_decimals=2,
@@ -28,7 +28,6 @@ CONFIG_SCHEMA = (
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(UltrasonicSensorComponent),
             cv.Required(CONF_TRIGGER_PIN): pins.gpio_output_pin_schema,
             cv.Required(CONF_ECHO_PIN): pins.internal_gpio_input_pin_schema,
             cv.Optional(CONF_TIMEOUT, default="2m"): cv.distance,
@@ -42,9 +41,8 @@ CONFIG_SCHEMA = (
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
 
     trigger = await cg.gpio_pin_expression(config[CONF_TRIGGER_PIN])
     cg.add(var.set_trigger_pin(trigger))
diff --git a/esphome/components/uptime/sensor.py b/esphome/components/uptime/sensor.py
index 16a1e4c125..103bc3a666 100644
--- a/esphome/components/uptime/sensor.py
+++ b/esphome/components/uptime/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import sensor
 from esphome.const import (
-    CONF_ID,
     ENTITY_CATEGORY_DIAGNOSTIC,
     STATE_CLASS_TOTAL_INCREASING,
     UNIT_SECOND,
@@ -12,24 +11,16 @@ from esphome.const import (
 uptime_ns = cg.esphome_ns.namespace("uptime")
 UptimeSensor = uptime_ns.class_("UptimeSensor", sensor.Sensor, cg.PollingComponent)
 
-CONFIG_SCHEMA = (
-    sensor.sensor_schema(
-        unit_of_measurement=UNIT_SECOND,
-        icon=ICON_TIMER,
-        accuracy_decimals=0,
-        state_class=STATE_CLASS_TOTAL_INCREASING,
-        entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
-    )
-    .extend(
-        {
-            cv.GenerateID(): cv.declare_id(UptimeSensor),
-        }
-    )
-    .extend(cv.polling_component_schema("60s"))
-)
+CONFIG_SCHEMA = sensor.sensor_schema(
+    UptimeSensor,
+    unit_of_measurement=UNIT_SECOND,
+    icon=ICON_TIMER,
+    accuracy_decimals=0,
+    state_class=STATE_CLASS_TOTAL_INCREASING,
+    entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
+).extend(cv.polling_component_schema("60s"))
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
diff --git a/esphome/components/vl53l0x/sensor.py b/esphome/components/vl53l0x/sensor.py
index 0ce3197366..7b485e3887 100644
--- a/esphome/components/vl53l0x/sensor.py
+++ b/esphome/components/vl53l0x/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import i2c, sensor
 from esphome.const import (
-    CONF_ID,
     STATE_CLASS_MEASUREMENT,
     UNIT_METER,
     ICON_ARROW_EXPAND_VERTICAL,
@@ -41,6 +40,7 @@ def check_timeout(value):
 
 CONFIG_SCHEMA = cv.All(
     sensor.sensor_schema(
+        VL53L0XSensor,
         unit_of_measurement=UNIT_METER,
         icon=ICON_ARROW_EXPAND_VERTICAL,
         accuracy_decimals=2,
@@ -48,7 +48,6 @@ CONFIG_SCHEMA = cv.All(
     )
     .extend(
         {
-            cv.GenerateID(): cv.declare_id(VL53L0XSensor),
             cv.Optional(CONF_SIGNAL_RATE_LIMIT, default=0.25): cv.float_range(
                 min=0.0, max=512.0, min_included=False, max_included=False
             ),
@@ -64,7 +63,7 @@ CONFIG_SCHEMA = cv.All(
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
     cg.add(var.set_signal_rate_limit(config[CONF_SIGNAL_RATE_LIMIT]))
     cg.add(var.set_long_range(config[CONF_LONG_RANGE]))
@@ -74,5 +73,4 @@ async def to_code(config):
         enable = await cg.gpio_pin_expression(config[CONF_ENABLE_PIN])
         cg.add(var.set_enable_pin(enable))
 
-    await sensor.register_sensor(var, config)
     await i2c.register_i2c_device(var, config)
diff --git a/esphome/components/wifi_signal/sensor.py b/esphome/components/wifi_signal/sensor.py
index 2097c21bd7..77fabf272e 100644
--- a/esphome/components/wifi_signal/sensor.py
+++ b/esphome/components/wifi_signal/sensor.py
@@ -2,7 +2,6 @@ import esphome.codegen as cg
 import esphome.config_validation as cv
 from esphome.components import sensor
 from esphome.const import (
-    CONF_ID,
     DEVICE_CLASS_SIGNAL_STRENGTH,
     ENTITY_CATEGORY_DIAGNOSTIC,
     STATE_CLASS_MEASUREMENT,
@@ -15,24 +14,16 @@ WiFiSignalSensor = wifi_signal_ns.class_(
     "WiFiSignalSensor", sensor.Sensor, cg.PollingComponent
 )
 
-CONFIG_SCHEMA = (
-    sensor.sensor_schema(
-        unit_of_measurement=UNIT_DECIBEL_MILLIWATT,
-        accuracy_decimals=0,
-        device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
-        state_class=STATE_CLASS_MEASUREMENT,
-        entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
-    )
-    .extend(
-        {
-            cv.GenerateID(): cv.declare_id(WiFiSignalSensor),
-        }
-    )
-    .extend(cv.polling_component_schema("60s"))
-)
+CONFIG_SCHEMA = sensor.sensor_schema(
+    WiFiSignalSensor,
+    unit_of_measurement=UNIT_DECIBEL_MILLIWATT,
+    accuracy_decimals=0,
+    device_class=DEVICE_CLASS_SIGNAL_STRENGTH,
+    state_class=STATE_CLASS_MEASUREMENT,
+    entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
+).extend(cv.polling_component_schema("60s"))
 
 
 async def to_code(config):
-    var = cg.new_Pvariable(config[CONF_ID])
+    var = await sensor.new_sensor(config)
     await cg.register_component(var, config)
-    await sensor.register_sensor(var, config)
diff --git a/esphome/components/xiaomi_cgpr1/binary_sensor.py b/esphome/components/xiaomi_cgpr1/binary_sensor.py
index 7f0aac873d..4297b7fc3b 100644
--- a/esphome/components/xiaomi_cgpr1/binary_sensor.py
+++ b/esphome/components/xiaomi_cgpr1/binary_sensor.py
@@ -7,12 +7,10 @@ from esphome.const import (
     CONF_DEVICE_CLASS,
     CONF_MAC_ADDRESS,
     CONF_ID,
-    DEVICE_CLASS_EMPTY,
     DEVICE_CLASS_BATTERY,
     DEVICE_CLASS_ILLUMINANCE,
     DEVICE_CLASS_MOTION,
     ENTITY_CATEGORY_DIAGNOSTIC,
-    ICON_EMPTY,
     UNIT_PERCENT,
     CONF_IDLE_TIME,
     CONF_ILLUMINANCE,
@@ -52,11 +50,12 @@ CONFIG_SCHEMA = cv.All(
                 unit_of_measurement=UNIT_MINUTE,
                 icon=ICON_TIMELAPSE,
                 accuracy_decimals=0,
-                device_class=DEVICE_CLASS_EMPTY,
                 entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
             ),
             cv.Optional(CONF_ILLUMINANCE): sensor.sensor_schema(
-                UNIT_LUX, ICON_EMPTY, 0, DEVICE_CLASS_ILLUMINANCE
+                unit_of_measurement=UNIT_LUX,
+                accuracy_decimals=0,
+                device_class=DEVICE_CLASS_ILLUMINANCE,
             ),
         }
     )
diff --git a/esphome/components/xiaomi_mjyd02yla/binary_sensor.py b/esphome/components/xiaomi_mjyd02yla/binary_sensor.py
index 1bedae26cf..6a7d6aae79 100644
--- a/esphome/components/xiaomi_mjyd02yla/binary_sensor.py
+++ b/esphome/components/xiaomi_mjyd02yla/binary_sensor.py
@@ -12,7 +12,6 @@ from esphome.const import (
     DEVICE_CLASS_ILLUMINANCE,
     ENTITY_CATEGORY_DIAGNOSTIC,
     STATE_CLASS_MEASUREMENT,
-    STATE_CLASS_NONE,
     UNIT_PERCENT,
     CONF_IDLE_TIME,
     CONF_ILLUMINANCE,
@@ -22,7 +21,7 @@ from esphome.const import (
 )
 
 DEPENDENCIES = ["esp32_ble_tracker"]
-AUTO_LOAD = ["xiaomi_ble"]
+AUTO_LOAD = ["xiaomi_ble", "sensor"]
 
 xiaomi_mjyd02yla_ns = cg.esphome_ns.namespace("xiaomi_mjyd02yla")
 XiaomiMJYD02YLA = xiaomi_mjyd02yla_ns.class_(
@@ -45,7 +44,6 @@ CONFIG_SCHEMA = cv.All(
                 unit_of_measurement=UNIT_MINUTE,
                 icon=ICON_TIMELAPSE,
                 accuracy_decimals=0,
-                state_class=STATE_CLASS_NONE,
             ),
             cv.Optional(CONF_BATTERY_LEVEL): sensor.sensor_schema(
                 unit_of_measurement=UNIT_PERCENT,
diff --git a/esphome/core/defines.h b/esphome/core/defines.h
index 574a8dcafe..aabb5510f4 100644
--- a/esphome/core/defines.h
+++ b/esphome/core/defines.h
@@ -57,6 +57,7 @@
 
 // ESP32-specific feature flags
 #ifdef USE_ESP32
+#define USE_ESP32_BLE_CLIENT
 #define USE_ESP32_BLE_SERVER
 #define USE_ESP32_CAMERA
 #define USE_ESP32_IGNORE_EFUSE_MAC_CRC