public void Register <T, TC, TE, TS>(Func <T> entityFactory)
            where T : ShardedEntity <TC, TE, TS>
            where TC : AbstractCommand
            where TE : AbstractEvent
            where TS : AbstractState
        {
            var proto           = entityFactory.Invoke();
            var entityTypeName  = proto.EntityTypeName;
            var entityClassType = proto.GetType();

            var alreadyRegistered = RegisteredTypeNames.GetOrAdd(entityTypeName, entityClassType);

            if (alreadyRegistered != null && alreadyRegistered != entityClassType)
            {
                throw new InvalidOperationException($"The entity type {nameof(T)} is already registered");
            }

            ReverseRegister.TryAdd(entityClassType, entityTypeName);

            var PassivateAfterIdleTimeout = ActorSystem.Settings.Config.GetConfig("wyvern.persistence")
                                            .GetTimeSpan("passivate-after-idle-timeout", TimeSpan.FromSeconds(100));

            const string snapshotPluginId = "";
            const string journalPluginId  = "";

            JoinCluster(ActorSystem);

            if (Role.ForAll(Cluster.Get(ActorSystem).SelfRoles.Contains))
            {
                ActorSystem.Log.Info("Cluster sharding initialized");
                var props = ShardedEntityActorProps.Create <T, TC, TE, TS>(
                    entityTypeName,
                    Option <string> .None,
                    entityFactory,
                    SnapshotAfter,
                    PassivateAfterIdleTimeout,
                    snapshotPluginId,
                    journalPluginId
                    );

                Sharding.Start(
                    entityTypeName,
                    props,
                    ShardingSettings,
                    ExtractEntityId,
                    ExtractShardId
                    );
            }
            else
            {
                ActorSystem.Log.Warning("Cluster proxy initialized");
                Sharding.StartProxy(
                    entityTypeName,
                    Role.Value,
                    ExtractEntityId,
                    ExtractShardId
                    );
            }
        }
        /// <summary>
        /// Get a reference to the entity with the given entityId
        /// </summary>
        /// <param name="entityId"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IShardedEntityReference RefFor <T>(string entityId)
            where T : class
        {
            if (!ReverseRegister.TryGetValue(typeof(T), out var entityName))
            {
                throw new InvalidOperationException($"{typeof(T)} not registered.");
            }

            return(new ShardedEntityReference(
                       entityId,
                       Sharding.ShardRegion(PrependRegistryName(entityName)),
                       ActorSystem,
                       AskTimeout
                       ));
        }