ChangeCalculator for calculating money denominations in change
The main problem with your code is that you've been encoding currency denomination data in C#'s type system: one type for each currency. That somehow led to a complicated interface/generics design, all without providing any real benefits. In fact, this design has several drawbacks:


Each new currency requires additional code (3 extra classes in total).
Apparently the core money-to-coins algorithm needs to be duplicated for each new currency - a proper design should make this reusable across different currencies.
Those generic interfaces aren't very useful: IChangeCalculator&lt;MoneyAmountPLN&gt; is not interchangeable with IChangeCalculator&lt;MoneyAmountEuro&gt;, despite being the 'same' interface.
The IChangeCalculator layer doesn't seem to provide much value: this could easily be done at the call-site.
Wrapping the results in an IMoneyAmount object on which the caller has to call a GetAmounts method seems a little pointless - why not just return those amounts directly?




This can be simplified a lot with a data-driven approach. The core money-to-coins method needs an amount and knowledge about a currency's denominations, and returns a list of coin (or bill) amounts:

public (int amount, decimal denomination)[] SplitIntoDenominations(
    decimal amount,
    decimal[] denominations)


Such a method can easily be reused for different currencies:

var euroDenominations = new decimal[] { 500m, 200m, 100m, ..., 0.05m, 0.02m, 0.01m };
// Denomination arrays can be stored anywhere: in hard-coded arrays,
// in a currency-name/denominations dictionary, or loaded from a file, etc.

var returned = SplitIntoDenominations(amount, euroDenominations);
foreach ((var amount, var denomination) in returned)
    Console.WriteLine($"{amount} coins of €{denomination}.");


You may find it useful to create a CurrencyInfo class that contains a denominations array as well as the name and symbol of the currency, and perhaps additional information, depending on your needs:

var euro = new CurrencyInfo("Euro", "€", new decimal[] { 500m, ..., 0.01m });
var dollar = new CurrencyInfo("Dollar", "$", new decimal[] { 100m, ..., 0.01m });


The same can be done for the return value of this method, if you find an array of named tuples to be insufficient. Again, this depends on your needs, but keep in mind that you only need a single class, regardless of currency.