@SuppressWarnings("unchecked")
  private <S, D> void propertyMap(Mapping mapping, MappingContextImpl<S, D> context) {
    MappingImpl mappingImpl = (MappingImpl) mapping;
    if (context.isShaded(mappingImpl.getPath())) return;

    Condition<Object, Object> condition = (Condition<Object, Object>) mapping.getCondition();
    if (condition == null)
      condition = (Condition<Object, Object>) context.getTypeMap().getPropertyCondition();
    if (condition == null && mapping.isSkipped()) return;

    Object source = resolveSourceValue(context, mapping);
    MappingContextImpl<Object, Object> propertyContext =
        propertyContextFor(context, source, mapping);

    if (condition != null) {
      if (!condition.applies(propertyContext)) {
        context.shadePath(mappingImpl.getPath());
        return;
      } else if (mapping.isSkipped()) return;
    }

    Converter<Object, Object> converter = (Converter<Object, Object>) mapping.getConverter();
    if (converter == null)
      converter = (Converter<Object, Object>) context.getTypeMap().getPropertyConverter();
    if (converter != null) context.shadePath(mappingImpl.getPath());
    else if (mapping instanceof SourceMapping) return;

    // Create destination for property context prior to mapping/conversion
    createDestinationViaProvider(propertyContext);

    // Set mapped/converted destination value
    setDestinationValue(context, propertyContext, mappingImpl, converter);
  }
  /** Performs a type mapping for the {@code typeMap} and {@code context}. */
  <S, D> D typeMap(MappingContextImpl<S, D> context, TypeMap<S, D> typeMap) {
    context.setTypeMap(typeMap);
    if (context.getDestination() == null && Types.isInstantiable(context.getDestinationType())) {
      D destination = createDestination(context);
      if (destination == null) return null;
    }

    @SuppressWarnings("unchecked")
    Condition<S, D> condition = (Condition<S, D>) typeMap.getCondition();
    Converter<S, D> converter = typeMap.getConverter();
    if (condition == null || condition.applies(context)) {
      if (converter != null) return convert(context, converter);

      converter = typeMap.getPreConverter();
      if (converter != null) convert(context, converter);

      for (Mapping mapping : typeMap.getMappings()) propertyMap(mapping, context);

      converter = typeMap.getPostConverter();
      if (converter != null) convert(context, converter);
    }

    return context.getDestination();
  }