public @Nullable TypeDescriptor getType(XmlElement context) {
    final XmlNSDescriptor nsDescriptor = getNSDescriptor(context);
    if (!(nsDescriptor instanceof XmlNSTypeDescriptorProvider)) return null;

    TypeDescriptor type = ((XmlNSTypeDescriptorProvider) nsDescriptor).getTypeDescriptor(myDescriptorTag);
    if (type == null) {
      String substAttr = myDescriptorTag.getAttributeValue("substitutionGroup");
      if (substAttr != null) {
        final String namespacePrefix = XmlUtil.findPrefixByQualifiedName(substAttr);
        final String namespace = namespacePrefix.isEmpty() ?
                                 getDefaultNamespace() :
                                 myDescriptorTag.getNamespaceByPrefix(namespacePrefix);
        final String local = XmlUtil.findLocalNameByQualifiedName(substAttr);
        final XmlElementDescriptorImpl originalElement = (XmlElementDescriptorImpl)((XmlNSDescriptorImpl)getNSDescriptor()).getElementDescriptor(local, namespace);
        if (originalElement != null && originalElement != this) {
          type = originalElement.getType(context);
        }
      }
    }
    else if (context instanceof XmlTag tag && nsDescriptor instanceof XmlNSDescriptorImpl) {
      // check for redefined descriptor
      if (!tag.getNamespace().equals(((XmlNSDescriptorImpl)nsDescriptor).getDefaultNamespace())) {
          XmlNSDescriptor descriptor = tag.getNSDescriptor(tag.getNamespace(), true);
          if (descriptor != nsDescriptor && descriptor instanceof XmlNSTypeDescriptorProvider) {
            TypeDescriptor typeDescriptor = ((XmlNSTypeDescriptorProvider)descriptor).getTypeDescriptor(myDescriptorTag);
            if (typeDescriptor != null && typeDescriptor.getDeclaration() != type.getDeclaration()) {
              return typeDescriptor;
            }
          }
      }
    }
    return type;
  }
public @Nullable TypeDescriptor getType(XmlElement context)