Here's an alternative, similar to EAV but with special considerations to "consistency" between products of the same type.
List of tables:
Products
Product-Types
Attributes
ProductTypes-Attributes-Allowed
Product-Attributes
Product-Attributes-Allowed has an FK to product types, FK to attributes. If an entry exists in the table for a specific combination of product type and attribute, that product type can have that attribute.
Product-Attributes directly references the Product and the ProductTypes-Attributes-Allowed table with FKs. The Product-Attributes table will hold the information specific to that product, while the Attributes table holds information about the attribute in general (display names, units, etc). You will have to jump an extra table to link the attribute values with the attributes "meta data," but you can at least enforce product type similarity.
EDIT, would not fit as a comment below:
@Willem-Aart These can all be properties of an Attribute, stored in the "Attribute" table. For example, you can have a string "DataType" that holds information about the data type of the value that is to be stored in the "Product-Attributes" table. This would require the data to be stored as a blob (or some other universally castable data type like char[]) in the Product-Attributes table. Or, you could have separate columns for each foreseen data type, and leave the "wrong" data types for the attribute blank. You can have a constraint to force at least one of the columns to be non-null.
To enforce a range of values, at least for numeric attributes, you can set those as columns in the Attribute table as well. "Max_Allowable_Value," for example.
Adding functionality/flexibility to your database often results in added complexity.