diff --git a/homeassistant/components/automation/__init__.py b/homeassistant/components/automation/__init__.py
index f4db7831235fb11c0beacab9a10a82c8fdfa7f0c..fd6a70cce46e589f4ab58ee225dc160071c5c966 100644
--- a/homeassistant/components/automation/__init__.py
+++ b/homeassistant/components/automation/__init__.py
@@ -314,6 +314,9 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
 class BaseAutomationEntity(ToggleEntity, ABC):
     """Base class for automation entities."""
 
+    _entity_component_unrecorded_attributes = frozenset(
+        (ATTR_LAST_TRIGGERED, ATTR_MODE, ATTR_CUR, ATTR_MAX, CONF_ID)
+    )
     raw_config: ConfigType | None
 
     @property
diff --git a/homeassistant/components/automation/recorder.py b/homeassistant/components/automation/recorder.py
deleted file mode 100644
index 3083d271d1ffb6458c95aa66ec599aecebc81e3d..0000000000000000000000000000000000000000
--- a/homeassistant/components/automation/recorder.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""Integration platform for recorder."""
-from __future__ import annotations
-
-from homeassistant.core import HomeAssistant, callback
-
-from . import ATTR_CUR, ATTR_LAST_TRIGGERED, ATTR_MAX, ATTR_MODE, CONF_ID
-
-
-@callback
-def exclude_attributes(hass: HomeAssistant) -> set[str]:
-    """Exclude extra attributes from being recorded in the database."""
-    return {ATTR_LAST_TRIGGERED, ATTR_MODE, ATTR_CUR, ATTR_MAX, CONF_ID}
diff --git a/homeassistant/components/recorder/db_schema.py b/homeassistant/components/recorder/db_schema.py
index e25c6d6dd5fbc3b4ff4e832cf2ab4a32c407f9b1..e992a683cb13cd229c5012fd4f1a60923fac90de 100644
--- a/homeassistant/components/recorder/db_schema.py
+++ b/homeassistant/components/recorder/db_schema.py
@@ -576,6 +576,8 @@ class StateAttributes(Base):
             integration_attrs := exclude_attrs_by_domain.get(entity_info["domain"])
         ):
             exclude_attrs |= integration_attrs
+        if state_info := state.state_info:
+            exclude_attrs |= state_info["unrecorded_attributes"]
         encoder = json_bytes_strip_null if dialect == PSQL_DIALECT else json_bytes
         bytes_result = encoder(
             {k: v for k, v in state.attributes.items() if k not in exclude_attrs}
diff --git a/homeassistant/core.py b/homeassistant/core.py
index a43fa1997c68123581a2a055624ef2c8b297a026..a50d43c1344f8091c5a84cc1b88663e58818b9c0 100644
--- a/homeassistant/core.py
+++ b/homeassistant/core.py
@@ -95,6 +95,7 @@ if TYPE_CHECKING:
     from .auth import AuthManager
     from .components.http import ApiConfig, HomeAssistantHTTP
     from .config_entries import ConfigEntries
+    from .helpers.entity import StateInfo
 
 
 STAGE_1_SHUTDOWN_TIMEOUT = 100
@@ -1249,6 +1250,7 @@ class State:
         last_updated: datetime.datetime | None = None,
         context: Context | None = None,
         validate_entity_id: bool | None = True,
+        state_info: StateInfo | None = None,
     ) -> None:
         """Initialize a new state."""
         state = str(state)
@@ -1267,6 +1269,7 @@ class State:
         self.last_updated = last_updated or dt_util.utcnow()
         self.last_changed = last_changed or self.last_updated
         self.context = context or Context()
+        self.state_info = state_info
         self.domain, self.object_id = split_entity_id(self.entity_id)
         self._as_dict: ReadOnlyDict[str, Collection[Any]] | None = None
 
@@ -1637,6 +1640,7 @@ class StateMachine:
         attributes: Mapping[str, Any] | None = None,
         force_update: bool = False,
         context: Context | None = None,
+        state_info: StateInfo | None = None,
     ) -> None:
         """Set the state of an entity, add entity if it does not exist.
 
@@ -1688,6 +1692,7 @@ class StateMachine:
             now,
             context,
             old_state is None,
+            state_info,
         )
         if old_state is not None:
             old_state.expire()
diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py
index 5ed16408388545334330fda568d8f8915108f199..9b16b0c24fdd242f1e4d0408b5db6c9ab3c71ab3 100644
--- a/homeassistant/helpers/entity.py
+++ b/homeassistant/helpers/entity.py
@@ -201,6 +201,12 @@ class EntityInfo(TypedDict):
     config_entry: NotRequired[str]
 
 
+class StateInfo(TypedDict):
+    """State info."""
+
+    unrecorded_attributes: frozenset[str]
+
+
 class EntityPlatformState(Enum):
     """The platform state of an entity."""
 
@@ -297,6 +303,22 @@ class Entity(ABC):
     # If entity is added to an entity platform
     _platform_state = EntityPlatformState.NOT_ADDED
 
+    # Attributes to exclude from recording, only set by base components, e.g. light
+    _entity_component_unrecorded_attributes: frozenset[str] = frozenset()
+    # Additional integration specific attributes to exclude from recording, set by
+    # platforms, e.g. a derived class in hue.light
+    _unrecorded_attributes: frozenset[str] = frozenset()
+    # Union of _entity_component_unrecorded_attributes and _unrecorded_attributes,
+    # set automatically by __init_subclass__
+    __combined_unrecorded_attributes: frozenset[str] = (
+        _entity_component_unrecorded_attributes | _unrecorded_attributes
+    )
+
+    # StateInfo. Set by EntityPlatform by calling async_internal_added_to_hass
+    # While not purely typed, it makes typehinting more useful for us
+    # and removes the need for constant None checks or asserts.
+    _state_info: StateInfo = None  # type: ignore[assignment]
+
     # Entity Properties
     _attr_assumed_state: bool = False
     _attr_attribution: str | None = None
@@ -321,6 +343,13 @@ class Entity(ABC):
     _attr_unique_id: str | None = None
     _attr_unit_of_measurement: str | None
 
+    def __init_subclass__(cls, **kwargs: Any) -> None:
+        """Initialize an Entity subclass."""
+        super().__init_subclass__(**kwargs)
+        cls.__combined_unrecorded_attributes = (
+            cls._entity_component_unrecorded_attributes | cls._unrecorded_attributes
+        )
+
     @property
     def should_poll(self) -> bool:
         """Return True if entity has to be polled for state.
@@ -875,7 +904,12 @@ class Entity(ABC):
 
         try:
             hass.states.async_set(
-                entity_id, state, attr, self.force_update, self._context
+                entity_id,
+                state,
+                attr,
+                self.force_update,
+                self._context,
+                self._state_info,
             )
         except InvalidStateError:
             _LOGGER.exception("Failed to set state, fall back to %s", STATE_UNKNOWN)
@@ -1081,15 +1115,19 @@ class Entity(ABC):
 
         Not to be extended by integrations.
         """
-        info: EntityInfo = {
+        entity_info: EntityInfo = {
             "domain": self.platform.platform_name,
             "custom_component": "custom_components" in type(self).__module__,
         }
 
         if self.platform.config_entry:
-            info["config_entry"] = self.platform.config_entry.entry_id
+            entity_info["config_entry"] = self.platform.config_entry.entry_id
 
-        entity_sources(self.hass)[self.entity_id] = info
+        entity_sources(self.hass)[self.entity_id] = entity_info
+
+        self._state_info = {
+            "unrecorded_attributes": self.__combined_unrecorded_attributes
+        }
 
         if self.registry_entry is not None:
             # This is an assert as it should never happen, but helps in tests