Under System > Configuration > Tax > Calculation Settings there are options for the order tax rules are applied, including Apply Customer Tax which can be either Before Discount or After Discount.

Tax Calculation Based On:

You can select which Tax rules will be applicable for orders that customers make on your e-store: shipping address, billing address, or your store’s shipping origin.
Select whether Catalog Prices and Shipping Prices will include or exclude Tax.
Define whether you would like to Apply Customer Tax before or after Discount.
Define if you would like to Apply Discount on Prices including of excluding Tax.
Magento2 Tax module Class Magento\Tax\Model\Config and that method applyTaxAfterDiscount() is responsible to apply tax after discount.

Class: Magento\Tax\Model\Config

Method: applyTaxAfterDiscount()

public function applyTaxAfterDiscount($store = null)
{
    return (bool)$this->_scopeConfig->getValue(
        self::CONFIG_XML_PATH_APPLY_AFTER_DISCOUNT,
        \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
        $store
    );
}

Summary of code flow (Stack)

  1. Magento\Tax\Helper\Data::applyTaxAfterDiscount()
  2. Magento\Tax\Model\Config::getCalculationSequence()
  3. Magento\Tax\Model\Calculation\AbstractAggregateCalculator::calculateWithTaxInPrice()
  4. Magento\Tax\Model\Calculation\AbstractAggregateCalculator::calculateWithTaxNotInPrice()
  5. Magento\Tax\Model\Calculation\UnitBaseCalculator::calculateWithTaxInPrice()
  6. Magento\Tax\Model\Calculation\UnitBaseCalculator::calculateWithTaxNotInPrice()
  7. Magento\Tax\Model\System\Message\Notifications::checkDiscountSettings()
  8. Magento\Tax\Model\System\Message\Notification\ApplyDiscountOnPrices::checkSettings()
  9. Magento\Tax\Model\System\Message\Notification\DiscountErrors::checkSettings()

Detail Code Flow

Magento\Tax\Helper\Data::applyTaxAfterDiscount()

public function applyTaxAfterDiscount($store = null)
{
    return $this->_config->applyTaxAfterDiscount($store);
}

Magento\Tax\Model\Config::getCalculationSequence()

public function getCalculationSequence($store = null)
{
    if ($this->applyTaxAfterDiscount($store)) {
        if ($this->discountTax($store)) {
            $seq = \Magento\Tax\Model\Calculation::CALC_TAX_AFTER_DISCOUNT_ON_INCL;
        } else {
            $seq = \Magento\Tax\Model\Calculation::CALC_TAX_AFTER_DISCOUNT_ON_EXCL;
        }
    } else {
        if ($this->discountTax($store)) {
            $seq = \Magento\Tax\Model\Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_INCL;
        } else {
            $seq = \Magento\Tax\Model\Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_EXCL;
        }
    }
    return $seq;
}

Magento\Tax\Model\Calculation\AbstractAggregateCalculator::calculateWithTaxInPrice()

protected function calculateWithTaxInPrice(QuoteDetailsItemInterface $item, $quantity, $round = true)
{
    $taxRateRequest = $this->getAddressRateRequest()->setProductClassId(
        $this->taxClassManagement->getTaxClassId($item->getTaxClassKey())
    );
    $rate = $this->calculationTool->getRate($taxRateRequest);
    $storeRate = $storeRate = $this->calculationTool->getStoreRate($taxRateRequest, $this->storeId);
    $discountTaxCompensationAmount = 0;
    $applyTaxAfterDiscount = $this->config->applyTaxAfterDiscount($this->storeId);
    $discountAmount = $item->getDiscountAmount();
    // Calculate $rowTotalInclTax
    $priceInclTax = $this->calculationTool->round($item->getUnitPrice());
    $rowTotalInclTax = $priceInclTax * $quantity;
    if (!$this->isSameRateAsStore($rate, $storeRate)) {
        $priceInclTax = $this->calculatePriceInclTax($priceInclTax, $storeRate, $rate, $round);
        $rowTotalInclTax = $priceInclTax * $quantity;
    }
    $rowTaxExact = $this->calculationTool->calcTaxAmount($rowTotalInclTax, $rate, true, false);
    $deltaRoundingType = self::KEY_REGULAR_DELTA_ROUNDING;
    if ($applyTaxAfterDiscount) {
        $deltaRoundingType = self::KEY_TAX_BEFORE_DISCOUNT_DELTA_ROUNDING;
    }
    $rowTax = $this->roundAmount($rowTaxExact, $rate, true, $deltaRoundingType, $round, $item);
    $rowTotal = $rowTotalInclTax - $rowTax;
    $price = $rowTotal / $quantity;
    if ($round) {
        $price = $this->calculationTool->round($price);
    }
    //Handle discount
    if ($applyTaxAfterDiscount) {
        //TODO: handle originalDiscountAmount
        $taxableAmount = max($rowTotalInclTax - $discountAmount, 0);
        $rowTaxAfterDiscount = $this->calculationTool->calcTaxAmount(
            $taxableAmount,
            $rate,
            true,
            false
        );
        $rowTaxAfterDiscount = $this->roundAmount(
            $rowTaxAfterDiscount,
            $rate,
            true,
            self::KEY_REGULAR_DELTA_ROUNDING,
            $round,
            $item
        );
        // Set discount tax compensation
        $discountTaxCompensationAmount = $rowTax - $rowTaxAfterDiscount;
        $rowTax = $rowTaxAfterDiscount;
    }
    // Calculate applied taxes
    /** @var  \Magento\Tax\Api\Data\AppliedTaxInterface[] $appliedTaxes */
    $appliedRates = $this->calculationTool->getAppliedRates($taxRateRequest);
    $appliedTaxes = $this->getAppliedTaxes($rowTax, $rate, $appliedRates);
    return $this->taxDetailsItemDataObjectFactory->create()
        ->setCode($item->getCode())
        ->setType($item->getType())
        ->setRowTax($rowTax)
        ->setPrice($price)
        ->setPriceInclTax($priceInclTax)
        ->setRowTotal($rowTotal)
        ->setRowTotalInclTax($rowTotalInclTax)
        ->setDiscountTaxCompensationAmount($discountTaxCompensationAmount)
        ->setAssociatedItemCode($item->getAssociatedItemCode())
        ->setTaxPercent($rate)
        ->setAppliedTaxes($appliedTaxes);
}

Magento\Tax\Model\Calculation\AbstractAggregateCalculator::calculateWithTaxNotInPrice()

protected function calculateWithTaxNotInPrice(QuoteDetailsItemInterface $item, $quantity, $round = true)
{
    $taxRateRequest = $this->getAddressRateRequest()->setProductClassId(
        $this->taxClassManagement->getTaxClassId($item->getTaxClassKey())
    );
    $rate = $this->calculationTool->getRate($taxRateRequest);
    $appliedRates = $this->calculationTool->getAppliedRates($taxRateRequest);
    $applyTaxAfterDiscount = $this->config->applyTaxAfterDiscount($this->storeId);
    $discountAmount = $item->getDiscountAmount();
    $discountTaxCompensationAmount = 0;
    // Calculate $rowTotal
    $price = $this->calculationTool->round($item->getUnitPrice());
    $rowTotal = $price * $quantity;
    $rowTaxes = [];
    $rowTaxesBeforeDiscount = [];
    $appliedTaxes = [];
    $rowTotalForTaxCalculation = $this->getPriceForTaxCalculation($item, $price) * $quantity;
    //Apply each tax rate separately
    foreach ($appliedRates as $appliedRate) {
        $taxId = $appliedRate['id'];
        $taxRate = $appliedRate['percent'];
        $rowTaxPerRate = $this->calculationTool->calcTaxAmount($rowTotalForTaxCalculation, $taxRate, false, false);
        $deltaRoundingType = self::KEY_REGULAR_DELTA_ROUNDING;
        if ($applyTaxAfterDiscount) {
            $deltaRoundingType = self::KEY_TAX_BEFORE_DISCOUNT_DELTA_ROUNDING;
        }
        $rowTaxPerRate = $this->roundAmount($rowTaxPerRate, $taxId, false, $deltaRoundingType, $round, $item);
        $rowTaxAfterDiscount = $rowTaxPerRate;
        //Handle discount
        if ($applyTaxAfterDiscount) {
            //TODO: handle originalDiscountAmount
            $taxableAmount = max($rowTotalForTaxCalculation - $discountAmount, 0);
            if ($taxableAmount && !$applyTaxAfterDiscount) {
                $taxableAmount = $rowTotalForTaxCalculation;
            }
            $rowTaxAfterDiscount = $this->calculationTool->calcTaxAmount(
                $taxableAmount,
                $taxRate,
                false,
                false
            );
            $rowTaxAfterDiscount = $this->roundAmount(
                $rowTaxAfterDiscount,
                $taxId,
                false,
                self::KEY_REGULAR_DELTA_ROUNDING,
                $round,
                $item
            );
        }
        $appliedTaxes[$taxId] = $this->getAppliedTax(
            $rowTaxAfterDiscount,
            $appliedRate
        );
        $rowTaxes[] = $rowTaxAfterDiscount;
        $rowTaxesBeforeDiscount[] = $rowTaxPerRate;
    }
    $rowTax = array_sum($rowTaxes);
    $rowTaxBeforeDiscount = array_sum($rowTaxesBeforeDiscount);
    $rowTotalInclTax = $rowTotal + $rowTaxBeforeDiscount;
    $priceInclTax = $rowTotalInclTax / $quantity;
    if ($round) {
        $priceInclTax = $this->calculationTool->round($priceInclTax);
    }
    return $this->taxDetailsItemDataObjectFactory->create()
        ->setCode($item->getCode())
        ->setType($item->getType())
        ->setRowTax($rowTax)
        ->setPrice($price)
        ->setPriceInclTax($priceInclTax)
        ->setRowTotal($rowTotal)
        ->setRowTotalInclTax($rowTotalInclTax)
        ->setDiscountTaxCompensationAmount($discountTaxCompensationAmount)
        ->setAssociatedItemCode($item->getAssociatedItemCode())
        ->setTaxPercent($rate)
        ->setAppliedTaxes($appliedTaxes);
}

Magento\Tax\Model\Calculation\UnitBaseCalculator::calculateWithTaxInPrice()

protected function calculateWithTaxInPrice(QuoteDetailsItemInterface $item, $quantity, $round = true)
{
    $taxRateRequest = $this->getAddressRateRequest()->setProductClassId(
        $this->taxClassManagement->getTaxClassId($item->getTaxClassKey())
    );
    $rate = $this->calculationTool->getRate($taxRateRequest);
    $storeRate = $storeRate = $this->calculationTool->getStoreRate($taxRateRequest, $this->storeId);
    // Calculate $priceInclTax
    $applyTaxAfterDiscount = $this->config->applyTaxAfterDiscount($this->storeId);
    $priceInclTax = $this->calculationTool->round($item->getUnitPrice());
    if (!$this->isSameRateAsStore($rate, $storeRate)) {
        $priceInclTax = $this->calculatePriceInclTax($priceInclTax, $storeRate, $rate, $round);
    }
    $uniTax = $this->calculationTool->calcTaxAmount($priceInclTax, $rate, true, false);
    $deltaRoundingType = self::KEY_REGULAR_DELTA_ROUNDING;
    if ($applyTaxAfterDiscount) {
        $deltaRoundingType = self::KEY_TAX_BEFORE_DISCOUNT_DELTA_ROUNDING;
    }
    $uniTax = $this->roundAmount($uniTax, $rate, true, $deltaRoundingType, $round, $item);
    $price = $priceInclTax - $uniTax;
    //Handle discount
    $discountTaxCompensationAmount = 0;
    $discountAmount = $item->getDiscountAmount();
    if ($applyTaxAfterDiscount) {
        //TODO: handle originalDiscountAmount
        $unitDiscountAmount = $discountAmount / $quantity;
        $taxableAmount = max($priceInclTax - $unitDiscountAmount, 0);
        $unitTaxAfterDiscount = $this->calculationTool->calcTaxAmount(
            $taxableAmount,
            $rate,
            true,
            false
        );
        $unitTaxAfterDiscount = $this->roundAmount(
            $unitTaxAfterDiscount,
            $rate,
            true,
            self::KEY_REGULAR_DELTA_ROUNDING,
            $round,
            $item
        );
        // Set discount tax compensation
        $unitDiscountTaxCompensationAmount = $uniTax - $unitTaxAfterDiscount;
        $discountTaxCompensationAmount = $unitDiscountTaxCompensationAmount * $quantity;
        $uniTax = $unitTaxAfterDiscount;
    }
    $rowTax = $uniTax * $quantity;
    // Calculate applied taxes
    /** @var  \Magento\Tax\Api\Data\AppliedTaxInterface[] $appliedTaxes */
    $appliedRates = $this->calculationTool->getAppliedRates($taxRateRequest);
    $appliedTaxes = $this->getAppliedTaxes($rowTax, $rate, $appliedRates);
    return $this->taxDetailsItemDataObjectFactory->create()
        ->setCode($item->getCode())
        ->setType($item->getType())
        ->setRowTax($rowTax)
        ->setPrice($price)
        ->setPriceInclTax($priceInclTax)
        ->setRowTotal($price * $quantity)
        ->setRowTotalInclTax($priceInclTax * $quantity)
        ->setDiscountTaxCompensationAmount($discountTaxCompensationAmount)
        ->setAssociatedItemCode($item->getAssociatedItemCode())
        ->setTaxPercent($rate)
        ->setAppliedTaxes($appliedTaxes);
}

Magento\Tax\Model\Calculation\UnitBaseCalculator::calculateWithTaxNotInPrice()

protected function calculateWithTaxNotInPrice(QuoteDetailsItemInterface $item, $quantity, $round = true)
{
    $taxRateRequest = $this->getAddressRateRequest()->setProductClassId(
        $this->taxClassManagement->getTaxClassId($item->getTaxClassKey())
    );
    $rate = $this->calculationTool->getRate($taxRateRequest);
    $appliedRates = $this->calculationTool->getAppliedRates($taxRateRequest);
    $applyTaxAfterDiscount = $this->config->applyTaxAfterDiscount($this->storeId);
    $discountAmount = $item->getDiscountAmount();
    $discountTaxCompensationAmount = 0;
    // Calculate $price
    $price = $this->calculationTool->round($item->getUnitPrice());
    $unitTaxes = [];
    $unitTaxesBeforeDiscount = [];
    $appliedTaxes = [];
    //Apply each tax rate separately
    foreach ($appliedRates as $appliedRate) {
        $taxId = $appliedRate['id'];
        $taxRate = $appliedRate['percent'];
        $unitTaxPerRate = $this->calculationTool->calcTaxAmount($price, $taxRate, false, false);
        $deltaRoundingType = self::KEY_REGULAR_DELTA_ROUNDING;
        if ($applyTaxAfterDiscount) {
            $deltaRoundingType = self::KEY_TAX_BEFORE_DISCOUNT_DELTA_ROUNDING;
        }
        $unitTaxPerRate = $this->roundAmount($unitTaxPerRate, $taxId, false, $deltaRoundingType, $round, $item);
        $unitTaxAfterDiscount = $unitTaxPerRate;
        //Handle discount
        if ($applyTaxAfterDiscount) {
            //TODO: handle originalDiscountAmount
            $unitDiscountAmount = $discountAmount / $quantity;
            $taxableAmount = max($price - $unitDiscountAmount, 0);
            $unitTaxAfterDiscount = $this->calculationTool->calcTaxAmount(
                $taxableAmount,
                $taxRate,
                false,
                false
            );
            $unitTaxAfterDiscount = $this->roundAmount(
                $unitTaxAfterDiscount,
                $taxId,
                false,
                self::KEY_REGULAR_DELTA_ROUNDING,
                $round,
                $item
            );
        }
        $appliedTaxes[$taxId] = $this->getAppliedTax(
            $unitTaxAfterDiscount * $quantity,
            $appliedRate
        );
        $unitTaxes[] = $unitTaxAfterDiscount;
        $unitTaxesBeforeDiscount[] = $unitTaxPerRate;
    }
    $unitTax = array_sum($unitTaxes);
    $unitTaxBeforeDiscount = array_sum($unitTaxesBeforeDiscount);
    $rowTax = $unitTax * $quantity;
    $priceInclTax = $price + $unitTaxBeforeDiscount;
    return $this->taxDetailsItemDataObjectFactory->create()
        ->setCode($item->getCode())
        ->setType($item->getType())
        ->setRowTax($rowTax)
        ->setPrice($price)
        ->setPriceInclTax($priceInclTax)
        ->setRowTotal($price * $quantity)
        ->setRowTotalInclTax($priceInclTax * $quantity)
        ->setDiscountTaxCompensationAmount($discountTaxCompensationAmount)
        ->setAssociatedItemCode($item->getAssociatedItemCode())
        ->setTaxPercent($rate)
        ->setAppliedTaxes($appliedTaxes);
}

Magento\Tax\Model\System\Message\Notifications::checkDiscountSettings()

public function checkDiscountSettings($store = null)
{
    return $this->taxConfig->applyTaxAfterDiscount($store);
}

Magento\Tax\Model\System\Message\Notification\ApplyDiscountOnPrices::checkSettings()

private function checkSettings($store = null)
{
    return $this->taxConfig->priceIncludesTax($store)
        || !$this->taxConfig->applyTaxAfterDiscount($store)
        || !$this->taxConfig->discountTax($store);
}

Magento\Tax\Model\System\Message\Notification\DiscountErrors::checkSettings()

private function checkSettings($store = null)
{
    return $this->taxConfig->applyTaxAfterDiscount($store);
}