Aggregate Inheritance and Polymorphism guidelines

Hello everyone.
My team has been successfully developed the first microservice in a soon-to-be larger micro-service ecosystem using the Axon Framework. Thus, the time has come for us to start developing the other services, that will communicate with this one.
The root of the problem arises from the fact that we make use of the same Entity( in a Bounded Context way of speaking) in both the applications. Apart from some common fields and the ability to handle 2 types of events, these two subtypes differ largely when it comes to command-handling and event-sourcing. So we thought that having a base AbstractAggreate with the common fields and and the 2 abstract EventSourcingHandler methods inside a common module will be the right choice for developing further.
However, I cannot put my finger on how exactly can we benefit from Aggregate Polymorphism and instantiation if the base AbstractAggregate, ATypeAggregate and BTypeAggregate all reside in 3 different Maven modules. How can we make sure that, inside module A we will instantiate ATypeAggregate and inside module B we will instantiate BTypeAggregate?
Here is a snippet on the base aggregate:

    public abstract class BaseAggregate implements Serializable {
    @AggregateIdentifier
    protected AggId partnerId;
    protected AggType discriminator;
    private String code;
    protected LegalForm legalForm;
   
    protected BusinessDetails businessDetails;
    private PersonalContact personalContact;
    private LanguageCode language = LanguageCode.getDefault();

    @EventSourcingHandler
    public abstract void on(RemoteSourceDataSyncedEvent event , @Autowired ModelMapper modelMapper);
}

And here is how the BType aggregate should look like:

    @Aggregate
    @Getter
    @Setter
    public class BType extends BaseAggregate {
     // private fields emitted for brevity

    @AggregateMember(type = Member1.class,
            eventForwardingMode = ForwardMatchingInstances.class)
    private Map<Long,Member1> addresses = new HashMap<>();

    @AggregateMember(type = Member2.class,
        eventForwardingMode = ForwardMatchingInstances.class)
    private Map<String, Member2> roles = new HashMap<>();

    @CommandHandler
    @CreationPolicy(AggregateCreationPolicy.CREATE_IF_MISSING)
    public void on(CreateBTypeCommand, @Autowired ModelMapper modelMapper) {
            //here we should handle creation of this subtype
    }

    @EventSourcingHandler
    @Override
    public void on(ERPPartnerDataSyncedEvent syncedEvent, @Autowired ModelMapper modelMapper) {
          //overridden way of handling the event applied from the base class
    }

AType and BType will have @CommandHandlers that will instatiate them differently, but each should be able to record that kind of SyncingEvent.
After a first attempt to implement such a behaviour, when dispatching a CreateBTypeCommand the command returns with error:

Failed to acquire lock for identifier(17006133), maximum attempts exceeded (6000)

After some debugging I found that it all goes well until this stage:

    protected LockAwareAggregate<T, A> doLoadOrCreate(String aggregateIdentifier,
                                                      Callable<T> factoryMethod) throws Exception {
        Lock lock = lockFactory.obtainLock(aggregateIdentifier);

Thank you in advance for taking the time to read my question and I am looking forward for any kind of help!

Hi Catalin,

Before we discuss polymorphic aggregates I would like to discuss the integration of the bounded context first. It is very much expected to model the common concept (can be entity or aggregate) independently in two different bounded contexts. For example, CourierOrderAggrgate in Courier bounded context and RestaurantOrderAggregate in Restaurant bounded context. The understanding of the concept of Order is unique per context and it is good to model/implement them independently. This way, two bounded contexts are integrated over the same concept. DRY principle does not work across bounded contexts. I like this definition BTW: BoundedContext. In my opinion, aggregates should not extend (polimorf) across bounded contexts. This will give you autonomy.
Please refer to the publically available Miro board (Miro | Online Whiteboard for Visual Collaboration) where we discuss bounded context integration in more formal way. The demo application is also available GitHub - AxonIQ/hotel-demo: Hotel booking application - Demo - Axon Framework & Axon Server.

In my opinion, you can squiz the power of polymorphic aggregates only within the bounded context, especially if the aggregate is going through many states, and you want to structure the state machine by modeling concrete aggregate as a state. I have some example project demonstrating this GitHub - idugalic/axon-statemachine-demo: Axon Finite State Machine Demo.

I hope, this helps.
Best,
Ivan