My favorite concept (because I'm about to implement it myself ;)) is the following:
An entity in the sense of a CES exists during runtime of gameplay only, i.e. it is part of the world. As such it is a UID and a couple of entries distributed over some sub-systems (named "services" in my engine). The entity instantiation process works on a resource kind of the Model class. A Model instance by itself is a composite of concrete Component instances. For each possible concrete Component sub-class there is a corresponding concrete ComponentType singleton-like instance. Such a ComponentType has a name (i.e. the one you use in JSON), is a factory for the belonging concrete Component, and can be understood as an outpost of one of the sub-systems.
Loading means to make Model instances, populate it with Component instances, and store them in the resource library. The ComponentType instances, addressed by their name, work as factories and de-serializer, so to say. The names of all used ComponentType instances are stored (indirectly) within the Model, too. There is another mechanism that may put objects into a Model instance. Components need not be specified in their entirety. Instead it is possible to express that some properties need to be defined at entity instantiation time (example: auto-generated individual name for each new instance of an orc-ish soldier).
Entity instantiation then means that the EntityServices sub-system is invoked to create a new entity by name. A parameter map is needed to be given at this moment if the Model of the requested entity has variables. The EntityServices creates a new entity UID, looks up the Model belonging to the given name in the resource library for Model instances, iterates the ComponentType instances for which a concrete Component instance is attached to the found Model instance, and invokes them to do their portion of entity creation. The entity UID, Model instance, and current Component instance is overhanded during this invocation. The ComponentType then investigates the Model instance for completeness, if necessary, does all allocation and initialization for the new entity inside the belonging sub-system, including eventually the filling of variables from the provided parameter map.
A ComponentType may return either with a Success, Failure, or Rework state. The former 2 are probably clear. However, it may happen that a ComponentType requires the set-up of another ComponentType (i.e. of another sub-system) to be done already, although those ComponentType wasn't iterated yet. So a ComponentType may tell the EntityServices that it want to be re-invoked once after the list of ComponentType is iterated first. What exactly happens within the sub-system during entity instantiation depends on the sub-system itself. It may be a cloning of Component as a prototype and linking the clone, or reserving and filling-in a place in a pre-allocated table, or whatever is suitable for the sub-system.
Notice please that the described mechanism doesn't require a 1:1 correspondence between sub-system and ComponentType; instead a 1:n correspondence is possible. Notice further that Component is just a data carrier, although it may define a behavior, but it does not perform any behavior.