I’m not aware of anything better with Java if we want to avoid increasing memory consumption for non-signal cases.
If memory isn’t a concern, then the instance field could be private final ComponentProperty<String> textProperty = ...; and then e.g. the setter implementation can be reduced to textProperty.set(text); But then we increase memory consumption by at least 16 bytes (assuming compressed OOPs but nothing from Lilliput) for each such field in each component instance. Most component features map directly to Element features so there aren’t actually too many such fields at least in the components that are used in large quantities (e.g. VerticalLayout, Span and Div have no own instance fields).
Another option for hiding the Object field would be to have static property descriptors that are used as lookup keys in an internal compact structure of Object values. Usage would then be like private static Property<String> TEXT = ...; and setState(TEXT, text); where setState is defined in a base class. A regular HashMap<Property<?>, Object> is not very compact in memory but we could use a Object[] as long as the property-to-index mapping for each component class could be stable. That is probably possible if we require that the property descriptors are static fields that we can look up with reflection from the component class (and its super classes). Memory overhead compared to regular instance fields would then be a constant 16 bytes per component instance instead of per signal-supporting instance field. The problem is that we’d want to put that field in Component so that you could use the feature also if you subclass some component that doesn’t need it. That means that every component instance would grow by at least 4 bytes for a pointer even if the value is null.