There are a couple of issues here.
-- The normal way to implement what you are talking about is with a cascading foreign-key constraint:
ALTER TABLE childtbl ADD CONSRAINT fk_child_parent
FOREIGN KEY (parentcol) REFERENCES parent (parentcol)
ON UPDATE CASCADE ON DELETE CASCADE
-- You have an AFTER trgger, which means that it fires after the statement has completed. Constraints are checked before triggers fire. Whence the error. You could code this as an INSTEAD OF trigger, but you should learn to master AFTER trigger first, so we skip that for now. Better is to disable the constraint to be able to conclude this particular exercise.
-- You trigger is incorrectly written. If you would disable the constraint and test, you would find that in deletes all products with a subcategory - except in the case when you delete all product sub-categories.
There are two problems in your DELETE statement, one related to your trigger and one not. Let's start with the one that is unrelated to the trigger. You have:
DELETE FROM DimProduct WHERE (DimProduct.ProductSubcategoryKey IN (SELECT DimProduct.ProductSubcategoryKey FROM DimProductSubcategory))
In the subquery, you are referring to the outer table. Thus, you essentially have
DELETE DimProduct WHERE ProductSubcategoryKey = ProductSubcategoryKey
Except for the case when the DimProductSubcategory table is empty.
On its own - and outside a trigger - this should be:
DELETE DimProduct
FROM DimProduct P
WHERE P.ProductSubcategoryKey IN (SELECT PS.ProductSubcategoryKey FROM DimProductSubcategory PS)
Here I have introduced aliases. You should start using aliases, as this makes your queries shorter and easier to read. Note that I'm now taking the ProductSubcategoryKey column from DimProductSubcategory.
Let's now look at the trigger-related error which also SQLZealots touched at in the answer above. In a trigger you have access to two virtual tables inserted and deleted. They have the same schema as the parent table of the trigger. The inserted table holds the row inserted by an INSERT statement and for an UPDATE statement it holds the after-image of the updated rows. The deleted table holds the rows deleted by a DELETE statement and the before-image of the rows affected by an UPDATE statement. Thus, you need to use deleted here, so that you only work with the categories that were actually deleted.